From 62b272251355d4e601e9fbda9fd04fab2268fd8d Mon Sep 17 00:00:00 2001 From: paczos Date: Tue, 30 May 2017 15:49:38 +0200 Subject: [PATCH 1/2] [android] - custom location engine fixes (#9139) --- .../mapboxsdk/constants/MapboxConstants.java | 2 +- .../com/mapbox/mapboxsdk/maps/MapboxMap.java | 29 ++++++--- .../mapboxsdk/maps/TrackingSettings.java | 43 ++++++++---- .../maps/widgets/MyLocationView.java | 65 +++++++++++++------ 4 files changed, 96 insertions(+), 43 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java index 0396defe74f..1ee59057d23 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java @@ -134,5 +134,5 @@ public class MapboxConstants { public static final String STATE_ATTRIBUTION_MARGIN_BOTTOM = "mapbox_atrrMarginBottom"; public static final String STATE_ATTRIBUTION_ENABLED = "mapbox_atrrEnabled"; public static final String STATE_LOCATION_CHANGE_ANIMATION_ENABLED = "mapbox_locationChangeAnimationEnabled"; - + public static final String STATE_USING_CUSTOM_LOCATION_SOURCE = "mapbox_usingCustomLocationSource"; } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java index 8e50adb777c..0d02642ee49 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java @@ -478,7 +478,7 @@ public void removeImage(String name) { */ @UiThread public void setMinZoomPreference( - @FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double minZoom) { + @FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double minZoom) { transform.setMinZoom(minZoom); } @@ -507,7 +507,7 @@ public double getMinZoomLevel() { */ @UiThread public void setMaxZoomPreference(@FloatRange(from = MapboxConstants.MINIMUM_ZOOM, - to = MapboxConstants.MAXIMUM_ZOOM) double maxZoom) { + to = MapboxConstants.MAXIMUM_ZOOM) double maxZoom) { transform.setMaxZoom(maxZoom); } @@ -1190,7 +1190,7 @@ public MarkerView addMarker(@NonNull BaseMarkerViewOptions markerOptions, @UiThread @NonNull public List addMarkerViews(@NonNull List markerViewOptions) { + BaseMarkerViewOptions> markerViewOptions) { return annotationManager.addMarkerViews(markerViewOptions, this); } @@ -1219,7 +1219,7 @@ public List getMarkerViewsInRect(@NonNull RectF rect) { @UiThread @NonNull public List addMarkers(@NonNull List markerOptionsList) { + BaseMarkerOptions> markerOptionsList) { return annotationManager.addMarkers(markerOptionsList, this); } @@ -1782,7 +1782,7 @@ public OnInfoWindowClickListener getOnInfoWindowClickListener() { */ @UiThread public void setOnInfoWindowLongClickListener(@Nullable OnInfoWindowLongClickListener - listener) { + listener) { annotationManager.getInfoWindowManager().setOnInfoWindowLongClickListener(listener); } @@ -1864,16 +1864,25 @@ public Location getMyLocation() { */ @UiThread public void setOnMyLocationChangeListener(@Nullable MapboxMap.OnMyLocationChangeListener - listener) { + listener) { trackingSettings.setOnMyLocationChangeListener(listener); } + /** + * Removes custom location source of the my-location layer and brings back default {@link LocationSource} + * location source. + * + */ + @UiThread + public void removeLocationSource() { + trackingSettings.removeLocationSource(); + } + /** * Replaces the location source of the my-location layer. * * @param locationSource A {@link LocationEngine} location source to use in the my-location layer. - * Set to null to use the default {@link LocationSource} - * location source. + * */ @UiThread public void setLocationSource(@Nullable LocationEngine locationSource) { @@ -1888,7 +1897,7 @@ public void setLocationSource(@Nullable LocationEngine locationSource) { */ @UiThread public void setOnMyLocationTrackingModeChangeListener( - @Nullable MapboxMap.OnMyLocationTrackingModeChangeListener listener) { + @Nullable MapboxMap.OnMyLocationTrackingModeChangeListener listener) { trackingSettings.setOnMyLocationTrackingModeChangeListener(listener); } @@ -1927,7 +1936,7 @@ public void snapshot(@NonNull SnapshotReadyCallback callback) { @UiThread @NonNull public List queryRenderedFeatures(@NonNull PointF coordinates, @Nullable String... - layerIds) { + layerIds) { return nativeMapView.queryRenderedFeatures(coordinates, layerIds, null); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java index 2e12de8dec9..998aa469b12 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java @@ -30,6 +30,7 @@ public final class TrackingSettings { private LocationEngine locationSource; private LocationEngineListener myLocationListener; private boolean locationChangeAnimationEnabled = true; + private boolean isCustomLocationSource; private boolean myLocationEnabled; private boolean dismissLocationTrackingOnGesture = true; @@ -58,22 +59,26 @@ void onSaveInstanceState(Bundle outState) { outState.putBoolean(MapboxConstants.STATE_MY_BEARING_TRACKING_DISMISS, isDismissBearingTrackingOnGesture()); outState.putBoolean(MapboxConstants.STATE_MY_LOCATION_ENABLED, isMyLocationEnabled()); outState.putBoolean(MapboxConstants.STATE_LOCATION_CHANGE_ANIMATION_ENABLED, isLocationChangeAnimationEnabled()); + outState.putBoolean(MapboxConstants.STATE_USING_CUSTOM_LOCATION_SOURCE, isCustomLocationSource()); } void onRestoreInstanceState(Bundle savedInstanceState) { try { - setMyLocationEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_MY_LOCATION_ENABLED)); + setMyLocationEnabled( + savedInstanceState.getBoolean(MapboxConstants.STATE_MY_LOCATION_ENABLED), + savedInstanceState.getBoolean(MapboxConstants.STATE_USING_CUSTOM_LOCATION_SOURCE) + ); } catch (SecurityException ignore) { // User did not accept location permissions } // noinspection ResourceType setMyLocationTrackingMode(savedInstanceState.getInt( - MapboxConstants.STATE_MY_LOCATION_TRACKING_MODE, MyLocationTracking.TRACKING_NONE)); + MapboxConstants.STATE_MY_LOCATION_TRACKING_MODE, MyLocationTracking.TRACKING_NONE)); // noinspection ResourceType setMyBearingTrackingMode(savedInstanceState.getInt( - MapboxConstants.STATE_MY_BEARING_TRACKING_MODE, MyBearingTracking.NONE)); + MapboxConstants.STATE_MY_BEARING_TRACKING_MODE, MyBearingTracking.NONE)); setDismissLocationTrackingOnGesture(savedInstanceState.getBoolean( - MapboxConstants.STATE_MY_LOCATION_TRACKING_DISMISS, true)); + MapboxConstants.STATE_MY_LOCATION_TRACKING_DISMISS, true)); setDismissBearingTrackingOnGesture(savedInstanceState.getBoolean( MapboxConstants.STATE_MY_BEARING_TRACKING_DISMISS, true)); setLocationChangeAnimationEnabled(savedInstanceState.getBoolean( @@ -242,9 +247,9 @@ public boolean isRotateGestureCurrentlyEnabled() { // The user settings are enabled AND; // EITHER bearing tracking is dismissed on gesture OR there is no bearing tracking return uiSettings.isRotateGesturesEnabled() - && (dismissBearingTrackingOnGesture - || myLocationView.getMyBearingTrackingMode() == MyBearingTracking.NONE - || myLocationView.getMyLocationTrackingMode() == MyLocationTracking.TRACKING_NONE); + && (dismissBearingTrackingOnGesture + || myLocationView.getMyBearingTrackingMode() == MyBearingTracking.NONE + || myLocationView.getMyLocationTrackingMode() == MyLocationTracking.TRACKING_NONE); } /** @@ -254,8 +259,8 @@ public boolean isRotateGestureCurrentlyEnabled() { */ public boolean isScrollGestureCurrentlyEnabled() { return uiSettings.isScrollGesturesEnabled() - && (dismissLocationTrackingOnGesture - || myLocationView.getMyLocationTrackingMode() == MyLocationTracking.TRACKING_NONE); + && (dismissLocationTrackingOnGesture + || myLocationView.getMyLocationTrackingMode() == MyLocationTracking.TRACKING_NONE); } /** @@ -339,6 +344,10 @@ public void onLocationChanged(Location location) { } } + public boolean isCustomLocationSource() { + return isCustomLocationSource; + } + void setOnMyLocationTrackingModeChangeListener(MapboxMap.OnMyLocationTrackingModeChangeListener listener) { this.onMyLocationTrackingModeChangeListener = listener; } @@ -357,20 +366,32 @@ boolean isMyLocationEnabled() { } void setMyLocationEnabled(boolean locationEnabled) { + setMyLocationEnabled(locationEnabled, isCustomLocationSource()); + } + + private void setMyLocationEnabled(boolean locationEnabled, boolean isCustomLocationSource) { if (!PermissionsManager.areLocationPermissionsGranted(myLocationView.getContext())) { Timber.e("Could not activate user location tracking: " - + "user did not accept the permission or permissions were not requested."); + + "user did not accept the permission or permissions were not requested."); return; } myLocationEnabled = locationEnabled; - myLocationView.setEnabled(locationEnabled); + this.isCustomLocationSource = isCustomLocationSource; + myLocationView.setEnabled(locationEnabled, isCustomLocationSource); } void setLocationSource(LocationEngine locationSource) { this.locationSource = locationSource; + this.isCustomLocationSource = true; myLocationView.setLocationSource(locationSource); } + void removeLocationSource() { + locationSource = LocationSource.getLocationEngine(myLocationView.getContext()); + this.isCustomLocationSource = false; + myLocationView.removeLocationSource(); + } + void update() { if (!myLocationView.isEnabled()) { return; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java index f648db413d9..043ceb9563b 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java @@ -71,12 +71,12 @@ public class MyLocationView extends View { private boolean locationChangeAnimationEnabled; private ValueAnimator.AnimatorUpdateListener invalidateSelfOnUpdateListener = - new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - invalidate(); - } - }; + new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + invalidate(); + } + }; private Drawable foregroundDrawable; private Drawable foregroundBearingDrawable; @@ -135,8 +135,8 @@ private void init(Context context) { // setup LayoutParams ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT); + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); setLayoutParams(lp); matrix = new Matrix(); @@ -166,7 +166,7 @@ public final void setForegroundDrawables(Drawable defaultDrawable, Drawable bear } if (defaultDrawable.getIntrinsicWidth() != bearingDrawable.getIntrinsicWidth() - || defaultDrawable.getIntrinsicHeight() != bearingDrawable.getIntrinsicHeight()) { + || defaultDrawable.getIntrinsicHeight() != bearingDrawable.getIntrinsicHeight()) { throw new RuntimeException("The dimensions from location and bearing drawables should be match"); } @@ -233,8 +233,8 @@ private void invalidateBounds() { int horizontalOffset = backgroundOffsetLeft - backgroundOffsetRight; int verticalOffset = backgroundOffsetTop - backgroundOffsetBottom; backgroundBounds = new Rect(-backgroundWidth / 2 + horizontalOffset, - -backgroundHeight / 2 + verticalOffset, backgroundWidth / 2 + horizontalOffset, backgroundHeight / 2 - + verticalOffset); + -backgroundHeight / 2 + verticalOffset, backgroundWidth / 2 + horizontalOffset, backgroundHeight / 2 + + verticalOffset); backgroundDrawable.setBounds(backgroundBounds); int foregroundWidth = foregroundDrawable.getIntrinsicWidth(); @@ -252,7 +252,7 @@ protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (location == null || foregroundBounds == null || backgroundBounds == null || accuracyAnimator == null - || screenLocation == null) { + || screenLocation == null) { // Not ready yet return; } @@ -391,9 +391,13 @@ public void setMapboxMap(MapboxMap mapboxMap) { @Override public void setEnabled(boolean enabled) { + setEnabled(enabled, false); + } + + public void setEnabled(boolean enabled, boolean isCustomLocationSource) { super.setEnabled(enabled); setVisibility(enabled ? View.VISIBLE : View.INVISIBLE); - toggleGps(enabled); + toggleGps(enabled, isCustomLocationSource); } @Override @@ -414,17 +418,23 @@ public void onRestoreInstanceState(Parcelable state) { super.onRestoreInstanceState(state); } + private void toggleGps(boolean enableGps) { + toggleGps(enableGps, mapboxMap != null && mapboxMap.getTrackingSettings().isCustomLocationSource()); + } + /** * Enabled / Disable GPS location updates along with updating the UI * * @param enableGps true if GPS is to be enabled, false if GPS is to be disabled */ - private void toggleGps(boolean enableGps) { - if (locationSource == null) { - locationSource = LocationSource.getLocationEngine(this.getContext()); - } - + private void toggleGps(boolean enableGps, boolean isCustomLocationSource) { if (enableGps) { + if (locationSource == null) { + if (!isCustomLocationSource) + locationSource = LocationSource.getLocationEngine(this.getContext()); + else + return; + } // Set an initial location if one available Location lastLocation = locationSource.getLastLocation(); @@ -438,15 +448,17 @@ private void toggleGps(boolean enableGps) { locationSource.addLocationEngineListener(userLocationListener); locationSource.activate(); + + locationSource.setPriority(LocationEnginePriority.HIGH_ACCURACY); } else { + if (locationSource == null) + return; // Disable location and user dot location = null; locationSource.removeLocationUpdates(); locationSource.removeLocationEngineListener(userLocationListener); locationSource.deactivate(); } - - locationSource.setPriority(LocationEnginePriority.HIGH_ACCURACY); } public Location getLocation() { @@ -497,6 +509,7 @@ public void setMyLocationTrackingMode(@MyLocationTracking.Mode int myLocationTra // center map directly mapboxMap.easeCamera(CameraUpdateFactory.newLatLng(new LatLng(location)), 0, false /*linear interpolator*/, null, true); + } else { // do not use interpolated location from tracking mode latLng = null; @@ -564,7 +577,17 @@ public void setContentPadding(int[] padding) { } public void setLocationSource(LocationEngine locationSource) { + toggleGps(false); this.locationSource = locationSource; + this.userLocationListener = null; + setEnabled(isEnabled(), true); + } + + public void removeLocationSource() { + toggleGps(false); + this.locationSource = LocationSource.getLocationEngine(getContext()); + this.userLocationListener = null; + setEnabled(isEnabled(), false); } private static class GpsLocationListener implements LocationEngineListener { @@ -838,7 +861,7 @@ void updateLatLng(@NonNull final Location location) { locationChangeAnimator.setDuration(0); } locationChangeAnimator.addUpdateListener(new MarkerCoordinateAnimatorListener(this, - latLng, newLocation + latLng, newLocation )); locationChangeAnimator.start(); latLng = newLocation; From b36c4cfaf15e4d184e2b2b5924828d93e969d452 Mon Sep 17 00:00:00 2001 From: Tobrun Van Nuland Date: Tue, 30 May 2017 16:22:04 +0200 Subject: [PATCH 2/2] Update to latest LOST dependency, fixup internal location source integration --- .../java/com/mapbox/mapboxsdk/Mapbox.java | 12 +- .../mapboxsdk/location/LocationSource.java | 40 +--- .../com/mapbox/mapboxsdk/maps/MapboxMap.java | 28 +-- .../mapboxsdk/maps/TrackingSettings.java | 42 +++-- .../maps/widgets/MyLocationView.java | 77 ++++---- .../maps/widgets/MyLocationViewTest.java | 4 +- .../activity/FeatureOverviewActivity.java | 52 ++--- .../userlocation/BaseLocationActivity.java | 46 +++-- .../CustomLocationEngineActivity.java | 36 +++- .../userlocation/MockLocationEngine.java | 125 ++++++++----- .../MyLocationDrawableActivity.java | 48 ++--- .../userlocation/MyLocationTintActivity.java | 3 - .../MyLocationToggleActivity.java | 65 ++----- .../MyLocationTrackingModeActivity.java | 177 ++++++++++++------ .../layout/activity_my_location_tracking.xml | 2 +- .../main/res/menu/menu_location_engine.xml | 20 ++ .../src/main/res/values/strings.xml | 3 + .../java/com/mapbox/mapboxsdk/MapboxTest.java | 5 +- platform/android/dependencies.gradle | 4 +- 19 files changed, 444 insertions(+), 345 deletions(-) create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_location_engine.xml diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java index 81134e9497d..17cd4e0dce5 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java @@ -30,6 +30,7 @@ public final class Mapbox { private Context context; private String accessToken; private Boolean connected; + private LocationSource locationSource; /** * Get an instance of Mapbox. @@ -45,8 +46,8 @@ public final class Mapbox { public static synchronized Mapbox getInstance(@NonNull Context context, @NonNull String accessToken) { if (INSTANCE == null) { Context appContext = context.getApplicationContext(); - INSTANCE = new Mapbox(appContext, accessToken); - LocationEngine locationEngine = LocationSource.getLocationEngine(appContext); + INSTANCE = new Mapbox(appContext, accessToken, new LocationSource(appContext)); + LocationEngine locationEngine = new LocationSource(appContext); locationEngine.setPriority(LocationEnginePriority.NO_POWER); MapboxTelemetry.getInstance().initialize( appContext, accessToken, BuildConfig.MAPBOX_EVENTS_USER_AGENT, locationEngine); @@ -55,9 +56,10 @@ public static synchronized Mapbox getInstance(@NonNull Context context, @NonNull return INSTANCE; } - Mapbox(@NonNull Context context, @NonNull String accessToken) { + Mapbox(@NonNull Context context, @NonNull String accessToken, LocationSource locationSource) { this.context = context; this.accessToken = accessToken; + this.locationSource = locationSource; } /** @@ -128,4 +130,8 @@ public static synchronized Boolean isConnected() { NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); return (activeNetwork != null && activeNetwork.isConnected()); } + + public static LocationSource getLocationSource() { + return INSTANCE.locationSource; + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java index 4e934fa3ccb..8416bd5b6cf 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java @@ -2,7 +2,7 @@ import android.content.Context; import android.location.Location; -import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import com.mapbox.services.android.telemetry.location.LocationEngine; import com.mapbox.services.android.telemetry.location.LocationEngineListener; @@ -13,10 +13,6 @@ import com.mapzen.android.lost.api.LocationServices; import com.mapzen.android.lost.api.LostApiClient; -import java.lang.ref.WeakReference; - -import timber.log.Timber; - /** * Manages locational updates. Contains methods to register and unregister location listeners. *
    @@ -35,40 +31,24 @@ public class LocationSource extends LocationEngine implements LostApiClient.ConnectionCallbacks, LocationListener { - private static LocationEngine instance; - - private WeakReference context; + private Context context; private LostApiClient lostApiClient; - private LocationSource(Context context) { + public LocationSource(Context context) { super(); - this.context = new WeakReference<>(context); - lostApiClient = new LostApiClient.Builder(this.context.get()) + this.context = context.getApplicationContext(); + lostApiClient = new LostApiClient.Builder(this.context) .addConnectionCallbacks(this) .build(); } - /** - * Get the LocationEngine instance. - * - * @param context a Context from which the application context is derived - * @return the LocationEngine instance - */ - public static synchronized LocationEngine getLocationEngine(@NonNull Context context) { - if (instance == null) { - instance = new LocationSource(context.getApplicationContext()); - } - - return instance; - } - /** * Activate the location engine which will connect whichever location provider you are using. You'll need to call * this before requesting user location updates using {@link LocationEngine#requestLocationUpdates()}. */ @Override public void activate() { - if (lostApiClient != null && !lostApiClient.isConnected()) { + if (!lostApiClient.isConnected()) { lostApiClient.connect(); } } @@ -80,7 +60,7 @@ public void activate() { */ @Override public void deactivate() { - if (lostApiClient != null && lostApiClient.isConnected()) { + if (lostApiClient.isConnected()) { lostApiClient.disconnect(); } } @@ -111,7 +91,6 @@ public void onConnected() { */ @Override public void onConnectionSuspended() { - Timber.d("Connection suspended."); } /** @@ -120,8 +99,9 @@ public void onConnectionSuspended() { * @return the last known location */ @Override + @Nullable public Location getLastLocation() { - if (lostApiClient.isConnected() && PermissionsManager.areLocationPermissionsGranted(context.get())) { + if (lostApiClient.isConnected() && PermissionsManager.areLocationPermissionsGranted(context)) { //noinspection MissingPermission return LocationServices.FusedLocationApi.getLastLocation(lostApiClient); } @@ -151,7 +131,7 @@ public void requestLocationUpdates() { request.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); } - if (lostApiClient.isConnected() && PermissionsManager.areLocationPermissionsGranted(context.get())) { + if (lostApiClient.isConnected() && PermissionsManager.areLocationPermissionsGranted(context)) { //noinspection MissingPermission LocationServices.FusedLocationApi.requestLocationUpdates(lostApiClient, request, this); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java index 0d02642ee49..8a708cb1869 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java @@ -37,7 +37,6 @@ import com.mapbox.mapboxsdk.constants.Style; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.geometry.LatLngBounds; -import com.mapbox.mapboxsdk.location.LocationSource; import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings; import com.mapbox.mapboxsdk.style.layers.Filter; import com.mapbox.mapboxsdk.style.layers.Layer; @@ -478,7 +477,7 @@ public void removeImage(String name) { */ @UiThread public void setMinZoomPreference( - @FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double minZoom) { + @FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double minZoom) { transform.setMinZoom(minZoom); } @@ -507,7 +506,7 @@ public double getMinZoomLevel() { */ @UiThread public void setMaxZoomPreference(@FloatRange(from = MapboxConstants.MINIMUM_ZOOM, - to = MapboxConstants.MAXIMUM_ZOOM) double maxZoom) { + to = MapboxConstants.MAXIMUM_ZOOM) double maxZoom) { transform.setMaxZoom(maxZoom); } @@ -1190,7 +1189,7 @@ public MarkerView addMarker(@NonNull BaseMarkerViewOptions markerOptions, @UiThread @NonNull public List addMarkerViews(@NonNull List markerViewOptions) { + BaseMarkerViewOptions> markerViewOptions) { return annotationManager.addMarkerViews(markerViewOptions, this); } @@ -1219,7 +1218,7 @@ public List getMarkerViewsInRect(@NonNull RectF rect) { @UiThread @NonNull public List addMarkers(@NonNull List markerOptionsList) { + BaseMarkerOptions> markerOptionsList) { return annotationManager.addMarkers(markerOptionsList, this); } @@ -1782,7 +1781,7 @@ public OnInfoWindowClickListener getOnInfoWindowClickListener() { */ @UiThread public void setOnInfoWindowLongClickListener(@Nullable OnInfoWindowLongClickListener - listener) { + listener) { annotationManager.getInfoWindowManager().setOnInfoWindowLongClickListener(listener); } @@ -1864,25 +1863,14 @@ public Location getMyLocation() { */ @UiThread public void setOnMyLocationChangeListener(@Nullable MapboxMap.OnMyLocationChangeListener - listener) { + listener) { trackingSettings.setOnMyLocationChangeListener(listener); } - /** - * Removes custom location source of the my-location layer and brings back default {@link LocationSource} - * location source. - * - */ - @UiThread - public void removeLocationSource() { - trackingSettings.removeLocationSource(); - } - /** * Replaces the location source of the my-location layer. * * @param locationSource A {@link LocationEngine} location source to use in the my-location layer. - * */ @UiThread public void setLocationSource(@Nullable LocationEngine locationSource) { @@ -1897,7 +1885,7 @@ public void setLocationSource(@Nullable LocationEngine locationSource) { */ @UiThread public void setOnMyLocationTrackingModeChangeListener( - @Nullable MapboxMap.OnMyLocationTrackingModeChangeListener listener) { + @Nullable MapboxMap.OnMyLocationTrackingModeChangeListener listener) { trackingSettings.setOnMyLocationTrackingModeChangeListener(listener); } @@ -1936,7 +1924,7 @@ public void snapshot(@NonNull SnapshotReadyCallback callback) { @UiThread @NonNull public List queryRenderedFeatures(@NonNull PointF coordinates, @Nullable String... - layerIds) { + layerIds) { return nativeMapView.queryRenderedFeatures(coordinates, layerIds, null); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java index 998aa469b12..bd0bf7c83b9 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java @@ -6,11 +6,11 @@ import android.support.annotation.Nullable; import android.support.annotation.UiThread; +import com.mapbox.mapboxsdk.Mapbox; import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.constants.MyBearingTracking; import com.mapbox.mapboxsdk.constants.MyLocationTracking; -import com.mapbox.mapboxsdk.location.LocationSource; import com.mapbox.mapboxsdk.maps.widgets.MyLocationView; import com.mapbox.services.android.telemetry.location.LocationEngine; import com.mapbox.services.android.telemetry.location.LocationEngineListener; @@ -48,7 +48,7 @@ public final class TrackingSettings { } void initialise(MapboxMapOptions options) { - locationSource = LocationSource.getLocationEngine(myLocationView.getContext()); + locationSource = Mapbox.getLocationSource(); setMyLocationEnabled(options.getLocationEnabled()); } @@ -65,20 +65,20 @@ void onSaveInstanceState(Bundle outState) { void onRestoreInstanceState(Bundle savedInstanceState) { try { setMyLocationEnabled( - savedInstanceState.getBoolean(MapboxConstants.STATE_MY_LOCATION_ENABLED), - savedInstanceState.getBoolean(MapboxConstants.STATE_USING_CUSTOM_LOCATION_SOURCE) + savedInstanceState.getBoolean(MapboxConstants.STATE_MY_LOCATION_ENABLED), + savedInstanceState.getBoolean(MapboxConstants.STATE_USING_CUSTOM_LOCATION_SOURCE) ); } catch (SecurityException ignore) { // User did not accept location permissions } // noinspection ResourceType setMyLocationTrackingMode(savedInstanceState.getInt( - MapboxConstants.STATE_MY_LOCATION_TRACKING_MODE, MyLocationTracking.TRACKING_NONE)); + MapboxConstants.STATE_MY_LOCATION_TRACKING_MODE, MyLocationTracking.TRACKING_NONE)); // noinspection ResourceType setMyBearingTrackingMode(savedInstanceState.getInt( - MapboxConstants.STATE_MY_BEARING_TRACKING_MODE, MyBearingTracking.NONE)); + MapboxConstants.STATE_MY_BEARING_TRACKING_MODE, MyBearingTracking.NONE)); setDismissLocationTrackingOnGesture(savedInstanceState.getBoolean( - MapboxConstants.STATE_MY_LOCATION_TRACKING_DISMISS, true)); + MapboxConstants.STATE_MY_LOCATION_TRACKING_DISMISS, true)); setDismissBearingTrackingOnGesture(savedInstanceState.getBoolean( MapboxConstants.STATE_MY_BEARING_TRACKING_DISMISS, true)); setLocationChangeAnimationEnabled(savedInstanceState.getBoolean( @@ -247,9 +247,9 @@ public boolean isRotateGestureCurrentlyEnabled() { // The user settings are enabled AND; // EITHER bearing tracking is dismissed on gesture OR there is no bearing tracking return uiSettings.isRotateGesturesEnabled() - && (dismissBearingTrackingOnGesture - || myLocationView.getMyBearingTrackingMode() == MyBearingTracking.NONE - || myLocationView.getMyLocationTrackingMode() == MyLocationTracking.TRACKING_NONE); + && (dismissBearingTrackingOnGesture + || myLocationView.getMyBearingTrackingMode() == MyBearingTracking.NONE + || myLocationView.getMyLocationTrackingMode() == MyLocationTracking.TRACKING_NONE); } /** @@ -259,8 +259,8 @@ public boolean isRotateGestureCurrentlyEnabled() { */ public boolean isScrollGestureCurrentlyEnabled() { return uiSettings.isScrollGesturesEnabled() - && (dismissLocationTrackingOnGesture - || myLocationView.getMyLocationTrackingMode() == MyLocationTracking.TRACKING_NONE); + && (dismissLocationTrackingOnGesture + || myLocationView.getMyLocationTrackingMode() == MyLocationTracking.TRACKING_NONE); } /** @@ -372,7 +372,7 @@ void setMyLocationEnabled(boolean locationEnabled) { private void setMyLocationEnabled(boolean locationEnabled, boolean isCustomLocationSource) { if (!PermissionsManager.areLocationPermissionsGranted(myLocationView.getContext())) { Timber.e("Could not activate user location tracking: " - + "user did not accept the permission or permissions were not requested."); + + "user did not accept the permission or permissions were not requested."); return; } myLocationEnabled = locationEnabled; @@ -381,17 +381,19 @@ private void setMyLocationEnabled(boolean locationEnabled, boolean isCustomLocat } void setLocationSource(LocationEngine locationSource) { + if (this.locationSource != null && this.locationSource.equals(locationSource)) { + // this source is already active + return; + } + + this.isCustomLocationSource = locationSource != null; + if (locationSource == null) { + locationSource = Mapbox.getLocationSource(); + } this.locationSource = locationSource; - this.isCustomLocationSource = true; myLocationView.setLocationSource(locationSource); } - void removeLocationSource() { - locationSource = LocationSource.getLocationEngine(myLocationView.getContext()); - this.isCustomLocationSource = false; - myLocationView.removeLocationSource(); - } - void update() { if (!myLocationView.isEnabled()) { return; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java index 043ceb9563b..9740679cf59 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java @@ -26,6 +26,7 @@ import android.view.View; import android.view.ViewGroup; +import com.mapbox.mapboxsdk.Mapbox; import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.constants.MyBearingTracking; @@ -40,6 +41,8 @@ import java.lang.ref.WeakReference; +import timber.log.Timber; + /** * UI element overlaid on a map to show the user's location. */ @@ -71,12 +74,12 @@ public class MyLocationView extends View { private boolean locationChangeAnimationEnabled; private ValueAnimator.AnimatorUpdateListener invalidateSelfOnUpdateListener = - new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - invalidate(); - } - }; + new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + invalidate(); + } + }; private Drawable foregroundDrawable; private Drawable foregroundBearingDrawable; @@ -135,8 +138,8 @@ private void init(Context context) { // setup LayoutParams ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT); + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); setLayoutParams(lp); matrix = new Matrix(); @@ -148,6 +151,10 @@ private void init(Context context) { compassListener = new CompassListener(context); } + public void init(LocationSource locationSource) { + this.locationSource = locationSource; + } + public final void setForegroundDrawables(Drawable defaultDrawable, Drawable bearingDrawable) { if (defaultDrawable == null) { return; @@ -166,7 +173,7 @@ public final void setForegroundDrawables(Drawable defaultDrawable, Drawable bear } if (defaultDrawable.getIntrinsicWidth() != bearingDrawable.getIntrinsicWidth() - || defaultDrawable.getIntrinsicHeight() != bearingDrawable.getIntrinsicHeight()) { + || defaultDrawable.getIntrinsicHeight() != bearingDrawable.getIntrinsicHeight()) { throw new RuntimeException("The dimensions from location and bearing drawables should be match"); } @@ -233,8 +240,8 @@ private void invalidateBounds() { int horizontalOffset = backgroundOffsetLeft - backgroundOffsetRight; int verticalOffset = backgroundOffsetTop - backgroundOffsetBottom; backgroundBounds = new Rect(-backgroundWidth / 2 + horizontalOffset, - -backgroundHeight / 2 + verticalOffset, backgroundWidth / 2 + horizontalOffset, backgroundHeight / 2 - + verticalOffset); + -backgroundHeight / 2 + verticalOffset, backgroundWidth / 2 + horizontalOffset, backgroundHeight / 2 + + verticalOffset); backgroundDrawable.setBounds(backgroundBounds); int foregroundWidth = foregroundDrawable.getIntrinsicWidth(); @@ -252,7 +259,7 @@ protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (location == null || foregroundBounds == null || backgroundBounds == null || accuracyAnimator == null - || screenLocation == null) { + || screenLocation == null) { // Not ready yet return; } @@ -430,16 +437,11 @@ private void toggleGps(boolean enableGps) { private void toggleGps(boolean enableGps, boolean isCustomLocationSource) { if (enableGps) { if (locationSource == null) { - if (!isCustomLocationSource) - locationSource = LocationSource.getLocationEngine(this.getContext()); - else + if (!isCustomLocationSource) { + locationSource = Mapbox.getLocationSource(); + } else { return; - } - // Set an initial location if one available - Location lastLocation = locationSource.getLastLocation(); - - if (lastLocation != null) { - setLocation(lastLocation); + } } if (userLocationListener == null) { @@ -447,16 +449,16 @@ private void toggleGps(boolean enableGps, boolean isCustomLocationSource) { } locationSource.addLocationEngineListener(userLocationListener); - locationSource.activate(); - locationSource.setPriority(LocationEnginePriority.HIGH_ACCURACY); + locationSource.activate(); } else { - if (locationSource == null) + if (locationSource == null) { return; + } // Disable location and user dot location = null; - locationSource.removeLocationUpdates(); locationSource.removeLocationEngineListener(userLocationListener); + locationSource.removeLocationUpdates(); locationSource.deactivate(); } } @@ -509,7 +511,6 @@ public void setMyLocationTrackingMode(@MyLocationTracking.Mode int myLocationTra // center map directly mapboxMap.easeCamera(CameraUpdateFactory.newLatLng(new LatLng(location)), 0, false /*linear interpolator*/, null, true); - } else { // do not use interpolated location from tracking mode latLng = null; @@ -580,14 +581,7 @@ public void setLocationSource(LocationEngine locationSource) { toggleGps(false); this.locationSource = locationSource; this.userLocationListener = null; - setEnabled(isEnabled(), true); - } - - public void removeLocationSource() { - toggleGps(false); - this.locationSource = LocationSource.getLocationEngine(getContext()); - this.userLocationListener = null; - setEnabled(isEnabled(), false); + setEnabled(isEnabled(), locationSource != null); } private static class GpsLocationListener implements LocationEngineListener { @@ -603,10 +597,12 @@ private static class GpsLocationListener implements LocationEngineListener { @Override public void onConnected() { MyLocationView locationView = userLocationView.get(); - if (locationView != null) { - LocationEngine locationEngine = locationSource.get(); - Location location = locationEngine.getLastLocation(); - locationView.setLocation(location); + LocationEngine locationEngine = locationSource.get(); + if (locationView != null && locationEngine != null) { + Location lastKnownLocation = locationEngine.getLastLocation(); + if (lastKnownLocation != null) { + locationView.setLocation(lastKnownLocation); + } locationEngine.requestLocationUpdates(); } } @@ -650,6 +646,9 @@ public void onPause() { } public boolean isSensorAvailable() { + if (rotationVectorSensor == null) { + Timber.e("Sensor.TYPE_ROTATION_VECTOR is missing from this device. Unable to use MyBearingTracking.COMPASS."); + } return rotationVectorSensor != null; } @@ -861,7 +860,7 @@ void updateLatLng(@NonNull final Location location) { locationChangeAnimator.setDuration(0); } locationChangeAnimator.addUpdateListener(new MarkerCoordinateAnimatorListener(this, - latLng, newLocation + latLng, newLocation )); locationChangeAnimator.start(); latLng = newLocation; diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/MyLocationViewTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/MyLocationViewTest.java index efd67db3562..fa19235ad07 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/MyLocationViewTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/MyLocationViewTest.java @@ -9,12 +9,12 @@ import android.support.test.espresso.ViewAction; import android.view.View; +import com.mapbox.mapboxsdk.Mapbox; import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.constants.MyBearingTracking; import com.mapbox.mapboxsdk.constants.MyLocationTracking; import com.mapbox.mapboxsdk.geometry.LatLng; -import com.mapbox.mapboxsdk.location.LocationSource; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.widgets.MyLocationView; import com.mapbox.mapboxsdk.testapp.R; @@ -104,7 +104,7 @@ public void perform(UiController uiController, View view) { mapboxMap.moveCamera( CameraUpdateFactory.newCameraPosition( new CameraPosition.Builder() - .target(new LatLng(LocationSource.getLocationEngine(view.getContext()).getLastLocation())) + .target(new LatLng(Mapbox.getLocationSource().getLastLocation())) .build() ) ); diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/FeatureOverviewActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/FeatureOverviewActivity.java index 074be98f5cd..f8617366a02 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/FeatureOverviewActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/FeatureOverviewActivity.java @@ -1,6 +1,5 @@ package com.mapbox.mapboxsdk.testapp.activity; -import android.Manifest; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; @@ -13,11 +12,10 @@ import android.support.annotation.NonNull; import android.support.annotation.StringRes; import android.support.design.widget.Snackbar; -import android.support.v4.app.ActivityCompat; -import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; +import android.text.TextUtils; import android.view.View; import com.mapbox.mapboxsdk.testapp.R; @@ -25,6 +23,8 @@ import com.mapbox.mapboxsdk.testapp.adapter.FeatureSectionAdapter; import com.mapbox.mapboxsdk.testapp.model.activity.Feature; import com.mapbox.mapboxsdk.testapp.utils.ItemClickSupport; +import com.mapbox.services.android.telemetry.permissions.PermissionsListener; +import com.mapbox.services.android.telemetry.permissions.PermissionsManager; import java.util.ArrayList; import java.util.Collections; @@ -40,19 +40,23 @@ * It uses tags as category and description to order the different entries. *

    */ -public class FeatureOverviewActivity extends AppCompatActivity { +public class FeatureOverviewActivity extends AppCompatActivity implements PermissionsListener { private static final String KEY_STATE_FEATURES = "featureList"; + private PermissionsManager permissionsManager; private RecyclerView recyclerView; private FeatureSectionAdapter sectionAdapter; private List features; + private int locationActivityInList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_feature_overview); + permissionsManager = new PermissionsManager(this); + recyclerView = (RecyclerView) findViewById(R.id.recyclerView); recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener()); @@ -119,22 +123,26 @@ private void startFeature(Feature feature) { } private boolean requestLocationPermission(final int positionInList) { - if ((ContextCompat.checkSelfPermission(FeatureOverviewActivity.this, - Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) - || (ContextCompat.checkSelfPermission(FeatureOverviewActivity.this, - Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)) { - ActivityCompat.requestPermissions(FeatureOverviewActivity.this, new String[] { - Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, positionInList); + if (isRuntimePermissionsRequired()) { + locationActivityInList = positionInList; + permissionsManager.requestLocationPermissions(this); return true; - } else { - return false; } + return false; } @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - if (!isRuntimePermissionsRequired() || isPermissionAccepted(grantResults)) { - startFeature(features.get(requestCode)); + public void onExplanationNeeded(List list) { + Snackbar.make( + findViewById(android.R.id.content), + TextUtils.join("", list.toArray()), + Snackbar.LENGTH_SHORT).show(); + } + + @Override + public void onPermissionResult(boolean isPermissionGranted) { + if (isPermissionGranted) { + startFeature(features.get(locationActivityInList)); } else { Snackbar.make( findViewById(android.R.id.content), @@ -143,12 +151,14 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis } } - private boolean isRuntimePermissionsRequired() { - return android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults); } - private boolean isPermissionAccepted(@NonNull int[] grantResults) { - return grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED; + private boolean isRuntimePermissionsRequired() { + return android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; } @Override @@ -219,13 +229,13 @@ private boolean requiresLocationPermission(String name, String category) { } }; - List requiresPermissionActvities = new ArrayList() { + List requiresPermissionActivities = new ArrayList() { { add(resources.getString(R.string.activity_double_map)); } }; - return requiresPermissionCategories.contains(category) || requiresPermissionActvities.contains(name); + return requiresPermissionCategories.contains(category) || requiresPermissionActivities.contains(name); } @Override diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/BaseLocationActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/BaseLocationActivity.java index a8d1772cb2e..f41e5e38f0f 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/BaseLocationActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/BaseLocationActivity.java @@ -1,25 +1,34 @@ package com.mapbox.mapboxsdk.testapp.activity.userlocation; -import android.Manifest; -import android.content.pm.PackageManager; import android.os.Build; +import android.os.Bundle; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.annotation.UiThread; -import android.support.v4.app.ActivityCompat; +import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; +import android.text.TextUtils; +import com.mapbox.services.android.telemetry.permissions.PermissionsListener; import com.mapbox.services.android.telemetry.permissions.PermissionsManager; -public abstract class BaseLocationActivity extends AppCompatActivity { +import java.util.List; - private static final int PERMISSIONS_LOCATION = 0; +public abstract class BaseLocationActivity extends AppCompatActivity implements PermissionsListener { + + private PermissionsManager permissionsManager; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + permissionsManager = new PermissionsManager(this); + } @UiThread protected final void toggleGps(boolean enableGps) { if (enableGps) { - if (!PermissionsManager.areLocationPermissionsGranted(this)) { - ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_COARSE_LOCATION, - Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_LOCATION); + if (!isRuntimePermissionsRequired()) { + permissionsManager.requestLocationPermissions(this); } else { enableLocation(true); } @@ -29,16 +38,21 @@ protected final void toggleGps(boolean enableGps) { } @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - if (requestCode == PERMISSIONS_LOCATION) { - if (!isRuntimePermissionsRequired() || isPermissionAccepted(grantResults)) { - enableLocation(true); - } - } + public void onExplanationNeeded(List list) { + Snackbar.make( + findViewById(android.R.id.content), + TextUtils.join("", list.toArray()), + Snackbar.LENGTH_SHORT).show(); + } + + @Override + public void onPermissionResult(boolean isPermissionAccepted) { + enableLocation(isPermissionAccepted); } - private boolean isPermissionAccepted(int[] grantResults) { - return grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED; + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults); } private boolean isRuntimePermissionsRequired() { diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/CustomLocationEngineActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/CustomLocationEngineActivity.java index 660404f1441..b0ea9c608bb 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/CustomLocationEngineActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/CustomLocationEngineActivity.java @@ -2,13 +2,15 @@ import android.os.Bundle; import android.support.design.widget.FloatingActionButton; +import android.view.Menu; +import android.view.MenuItem; import android.view.View; +import com.mapbox.mapboxsdk.Mapbox; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; import com.mapbox.mapboxsdk.testapp.R; -import com.mapbox.services.android.telemetry.location.LocationEngine; public class CustomLocationEngineActivity extends BaseLocationActivity { @@ -16,22 +18,18 @@ public class CustomLocationEngineActivity extends BaseLocationActivity { private MapboxMap mapboxMap; private FloatingActionButton locationToggleFab; - private LocationEngine locationServices; - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_custom_location_engine); - locationServices = new MockLocationEngine(); - mapView = (MapView) findViewById(R.id.mapView); mapView.onCreate(savedInstanceState); mapView.getMapAsync(new OnMapReadyCallback() { @Override public void onMapReady(MapboxMap map) { mapboxMap = map; - mapboxMap.setLocationSource(locationServices); + mapboxMap.setLocationSource(MockLocationEngine.getInstance()); } }); @@ -40,7 +38,7 @@ public void onMapReady(MapboxMap map) { @Override public void onClick(View view) { if (mapboxMap != null) { - toggleGps(!mapboxMap.isMyLocationEnabled()); + enableLocation(!mapboxMap.isMyLocationEnabled()); } } }); @@ -56,6 +54,30 @@ protected void enableLocation(boolean enabled) { } } + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_location_engine, menu); + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (mapboxMap != null) { + int itemId = item.getItemId(); + if (itemId == R.id.action_id_location_source_lost) { + mapboxMap.setLocationSource(Mapbox.getLocationSource()); + return true; + } else if (itemId == R.id.action_id_location_source_mock) { + mapboxMap.setLocationSource(MockLocationEngine.getInstance()); + return true; + } else if (itemId == R.id.action_id_location_source_null) { + mapboxMap.setLocationSource(null); + return true; + } + } + return super.onOptionsItemSelected(item); + } + @Override protected void onStart() { super.onStart(); diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MockLocationEngine.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MockLocationEngine.java index b02b35b0d02..da3c78b07a5 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MockLocationEngine.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MockLocationEngine.java @@ -1,38 +1,55 @@ package com.mapbox.mapboxsdk.testapp.activity.userlocation; - +import android.animation.AnimatorListenerAdapter; +import android.animation.TypeEvaluator; +import android.animation.ValueAnimator; import android.location.Location; -import android.os.Handler; import com.mapbox.services.android.telemetry.location.LocationEngine; import com.mapbox.services.android.telemetry.location.LocationEngineListener; +import timber.log.Timber; + /** - * Sample LocationEngine that provides mocked locations simulating GPS updates + * Sample LocationEngine that provides mocked LOCATIONS simulating GPS updates */ public class MockLocationEngine extends LocationEngine { + private static MockLocationEngine INSTANCE; + + private final LocationAnimator locationAnimator; + private boolean running; + private static int counter; + + MockLocationEngine(Location start, Location end) { + locationAnimator = new LocationAnimator(start, end, new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + for (LocationEngineListener listener : locationListeners) { + listener.onLocationChanged((Location) animation.getAnimatedValue()); + } + } + }); + } + + public static synchronized MockLocationEngine getInstance() { + if (INSTANCE == null) { + INSTANCE = new MockLocationEngine( + MockLocationEngine.createLocation(40.416913, -3.703861), + MockLocationEngine.createLocation(39.461643, -0.368041) + ); + } + return INSTANCE; + } - // Mocked data - private static final int UPDATE_INTERVAL_MS = 1000; - private static final double[][] locations = new double[][] { - new double[] {39.489309, -0.360415}, - new double[] {39.492469, -0.358777}, - new double[] {40.393285, -3.707260}, - new double[] {40.394374, -3.707767}, - new double[] {40.398012, -3.715943}, - new double[] {40.416913, -3.703861}}; - - private Handler handler; - int currentIndex; - - public MockLocationEngine() { - super(); + public static Location createLocation(double latitude, double longitude) { + Location location = new Location(MockLocationEngine.class.getSimpleName()); + location.setLatitude(latitude); + location.setLongitude(longitude); + return location; } @Override public void activate() { - currentIndex = 0; - // "Connection" is immediate here for (LocationEngineListener listener : locationListeners) { listener.onConnected(); @@ -41,7 +58,6 @@ public void activate() { @Override public void deactivate() { - handler = null; } @Override @@ -51,44 +67,61 @@ public boolean isConnected() { @Override public Location getLastLocation() { - return getNextLocation(); + return null; } @Override public void requestLocationUpdates() { - // Fake regular updates with a handler - handler = new Handler(); - handler.postDelayed(new LocationUpdateRunnable(), UPDATE_INTERVAL_MS); + if (!running) { + locationAnimator.start(); + running = true; + } } @Override public void removeLocationUpdates() { - if (handler != null) { - handler.removeCallbacksAndMessages(null); + if (running) { + locationAnimator.stop(); + running = false; + Timber.e("LOC %s", counter); } } - private Location getNextLocation() { - // Build the next location and rotate the index - Location location = new Location(MockLocationEngine.class.getSimpleName()); - location.setLatitude(locations[currentIndex][0]); - location.setLongitude(locations[currentIndex][1]); - currentIndex = (currentIndex == locations.length - 1 ? 0 : currentIndex + 1); - return location; - } + private static class LocationAnimator extends AnimatorListenerAdapter { - private class LocationUpdateRunnable implements Runnable { - @Override - public void run() { - // Notify of an update - Location location = getNextLocation(); - for (LocationEngineListener listener : locationListeners) { - listener.onLocationChanged(location); - } + private static final long DURATION_ANIMATION = 10000; + private final ValueAnimator locationAnimator; + private long animationTime; + + LocationAnimator(Location start, Location end, ValueAnimator.AnimatorUpdateListener listener) { + locationAnimator = ValueAnimator.ofObject(new LocationEvaluator(), start, end); + locationAnimator.setDuration(DURATION_ANIMATION); + locationAnimator.addUpdateListener(listener); + locationAnimator.addListener(this); + } + + void start() { + locationAnimator.start(); + locationAnimator.setCurrentPlayTime(animationTime); + } + + void stop() { + animationTime = locationAnimator.getCurrentPlayTime(); + locationAnimator.cancel(); + } + + private static class LocationEvaluator implements TypeEvaluator { + + private Location location = new Location(MockLocationEngine.class.getSimpleName()); - if (handler != null) { - // Schedule the next update - handler.postDelayed(new LocationUpdateRunnable(), UPDATE_INTERVAL_MS); + @Override + public Location evaluate(float fraction, Location startValue, Location endValue) { + counter++; + location.setLatitude(startValue.getLatitude() + + ((endValue.getLatitude() - startValue.getLatitude()) * fraction)); + location.setLongitude(startValue.getLongitude() + + ((endValue.getLongitude() - startValue.getLongitude()) * fraction)); + return location; } } } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationDrawableActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationDrawableActivity.java index 5560f81fa90..86574341277 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationDrawableActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationDrawableActivity.java @@ -11,33 +11,35 @@ import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.constants.Style; import com.mapbox.mapboxsdk.geometry.LatLng; -import com.mapbox.mapboxsdk.location.LocationSource; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.MapboxMapOptions; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; import com.mapbox.mapboxsdk.testapp.R; -import com.mapbox.services.android.telemetry.location.LocationEngineListener; + +import com.mapzen.android.lost.api.LocationListener; +import com.mapzen.android.lost.api.LocationRequest; +import com.mapzen.android.lost.api.LocationServices; +import com.mapzen.android.lost.api.LostApiClient; /** * Test activity showcasing how to change the MyLocationView drawable. */ -public class MyLocationDrawableActivity extends BaseLocationActivity implements LocationEngineListener { +public class MyLocationDrawableActivity extends BaseLocationActivity implements LostApiClient.ConnectionCallbacks, + LocationListener { private MapView mapView; private MapboxMap mapboxMap; + private LostApiClient lostApiClient; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my_location_customization); - findViewById(R.id.progress).setVisibility(View.GONE); MapboxMapOptions mapboxMapOptions = new MapboxMapOptions(); mapboxMapOptions.styleUrl(Style.MAPBOX_STREETS); - - // configure MyLocationView drawables mapboxMapOptions.myLocationForegroundDrawable(ContextCompat.getDrawable(this, R.drawable.ic_android)); mapboxMapOptions.myLocationBackgroundDrawable(ContextCompat.getDrawable(this, R.drawable.ic_android)); mapboxMapOptions.myLocationForegroundTintColor(Color.GREEN); @@ -45,7 +47,6 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { mapboxMapOptions.myLocationBackgroundPadding(new int[] {0, 0, (int) getResources().getDimension(R.dimen.locationview_background_drawable_padding), (int) getResources().getDimension(R.dimen.locationview_background_drawable_padding)}); - mapboxMapOptions.myLocationAccuracyTint(Color.RED); mapboxMapOptions.myLocationAccuracyAlpha(155); @@ -66,29 +67,29 @@ public void onMapReady(MapboxMap map) { @Override protected void enableLocation(boolean enabled) { - if (enabled) { - mapboxMap.setMyLocationEnabled(true); - Location location = mapboxMap.getMyLocation(); - if (location != null) { - onLocationChanged(location); - } else { - LocationSource.getLocationEngine(this).addLocationEngineListener(this); - } - } else { - mapboxMap.setMyLocationEnabled(false); + mapboxMap.setMyLocationEnabled(enabled); + if (lostApiClient == null) { + lostApiClient = new LostApiClient.Builder(this).addConnectionCallbacks(this).build(); + lostApiClient.connect(); } } @Override public void onConnected() { - // Nothing + LocationRequest request = LocationRequest.create() + .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) + .setInterval(5000) + .setSmallestDisplacement(10); + LocationServices.FusedLocationApi.requestLocationUpdates(lostApiClient, request, this); } @Override public void onLocationChanged(Location location) { - if (mapboxMap != null) { - mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(location), 14)); - } + mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(location), 14)); + } + + @Override + public void onConnectionSuspended() { } @Override @@ -113,6 +114,11 @@ protected void onPause() { protected void onStop() { super.onStop(); mapView.onStop(); + if (lostApiClient.isConnected()) { + LocationServices.FusedLocationApi.removeLocationUpdates(lostApiClient, this); + lostApiClient.disconnect(); + } + lostApiClient.unregisterConnectionCallbacks(this); } @Override diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTintActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTintActivity.java index a219b369f62..44ee0308856 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTintActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTintActivity.java @@ -13,7 +13,6 @@ import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.constants.MyLocationTracking; import com.mapbox.mapboxsdk.geometry.LatLng; -import com.mapbox.mapboxsdk.location.LocationSource; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; @@ -133,7 +132,6 @@ public void onLocationChanged(Location location) { protected void onStart() { super.onStart(); mapView.onStart(); - LocationSource.getLocationEngine(this).addLocationEngineListener(this); } @Override @@ -151,7 +149,6 @@ public void onPause() { @Override protected void onStop() { super.onStop(); - LocationSource.getLocationEngine(this).removeLocationEngineListener(this); mapView.onStop(); } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationToggleActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationToggleActivity.java index ac6c346a88c..d465d676f73 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationToggleActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationToggleActivity.java @@ -1,19 +1,15 @@ package com.mapbox.mapboxsdk.testapp.activity.userlocation; -import android.location.Location; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; import android.view.View; -import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; -import com.mapbox.mapboxsdk.geometry.LatLng; -import com.mapbox.mapboxsdk.location.LocationSource; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; import com.mapbox.mapboxsdk.testapp.R; -import com.mapbox.services.android.telemetry.location.LocationEngine; -import com.mapbox.services.android.telemetry.location.LocationEngineListener; + +import timber.log.Timber; public class MyLocationToggleActivity extends BaseLocationActivity { @@ -21,16 +17,11 @@ public class MyLocationToggleActivity extends BaseLocationActivity { private MapboxMap mapboxMap; private FloatingActionButton locationToggleFab; - private LocationEngine locationServices; - private LocationEngineListener locationListener; - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my_location_toggle); - locationServices = LocationSource.getLocationEngine(this); - mapView = (MapView) findViewById(R.id.mapView); mapView.onCreate(savedInstanceState); mapView.getMapAsync(new OnMapReadyCallback() { @@ -51,6 +42,17 @@ public void onClick(View view) { }); } + @Override + protected void enableLocation(boolean enabled) { + Timber.e("Enabling location: %s", enabled); + mapboxMap.setMyLocationEnabled(enabled); + if (enabled) { + locationToggleFab.setImageResource(R.drawable.ic_location_disabled); + } else { + locationToggleFab.setImageResource(R.drawable.ic_my_location); + } + } + @Override protected void onStart() { super.onStart(); @@ -85,11 +87,6 @@ protected void onSaveInstanceState(Bundle outState) { protected void onDestroy() { super.onDestroy(); mapView.onDestroy(); - // Ensure no memory leak occurs if we register the location listener but the call hasn't - // been made yet. - if (locationListener != null) { - locationServices.removeLocationEngineListener(locationListener); - } } @Override @@ -98,40 +95,4 @@ public void onLowMemory() { mapView.onLowMemory(); } - @Override - protected void enableLocation(boolean enabled) { - if (enabled) { - // To move the camera instantly, we attempt to get the last known location and either - // ease or animate the camera to that position depending on the zoom level. - Location lastLocation = LocationSource.getLocationEngine(this).getLastLocation(); - - if (lastLocation != null) { - if (mapboxMap.getCameraPosition().zoom > 15.99) { - mapboxMap.easeCamera(CameraUpdateFactory.newLatLng(new LatLng(lastLocation)), 1000); - } else { - mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lastLocation), 16), 1000); - } - } else { - locationListener = new LocationEngineListener() { - @Override - public void onConnected() { - // Nothing - } - - @Override - public void onLocationChanged(Location location) { - if (location != null) { - mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(location), 16)); - locationServices.removeLocationEngineListener(this); - } - } - }; - locationServices.addLocationEngineListener(locationListener); - } - locationToggleFab.setImageResource(R.drawable.ic_location_disabled); - } else { - locationToggleFab.setImageResource(R.drawable.ic_my_location); - } - mapboxMap.setMyLocationEnabled(enabled); - } } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTrackingModeActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTrackingModeActivity.java index 3a3301b87ff..91f3de08373 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTrackingModeActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTrackingModeActivity.java @@ -1,5 +1,6 @@ package com.mapbox.mapboxsdk.testapp.activity.userlocation; +import android.location.Location; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v7.app.ActionBar; @@ -13,14 +14,22 @@ import android.widget.Spinner; import android.widget.Toast; +import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.constants.MyBearingTracking; import com.mapbox.mapboxsdk.constants.MyLocationTracking; +import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; import com.mapbox.mapboxsdk.maps.TrackingSettings; import com.mapbox.mapboxsdk.maps.UiSettings; import com.mapbox.mapboxsdk.testapp.R; +import com.mapzen.android.lost.api.LocationListener; +import com.mapzen.android.lost.api.LocationRequest; +import com.mapzen.android.lost.api.LocationServices; +import com.mapzen.android.lost.api.LostApiClient; + +import timber.log.Timber; /** * Test activity showcasing the different tracking modes the SDK exposes. @@ -29,7 +38,11 @@ * using gesture configurations. *

    */ -public class MyLocationTrackingModeActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener { +public class MyLocationTrackingModeActivity extends AppCompatActivity implements + AdapterView.OnItemSelectedListener, OnMapReadyCallback, LostApiClient.ConnectionCallbacks, LocationListener { + + // Testing for user defined LostApiClient + private LostApiClient lostApiClient; public static final int TRACKING_NONE_INDEX = 0; public static final int TRACKING_FOLLOW_INDEX = 1; @@ -41,6 +54,7 @@ public class MyLocationTrackingModeActivity extends AppCompatActivity implements private MapboxMap mapboxMap; private Spinner locationSpinner; private Spinner bearingSpinner; + private boolean firstRun = true; private MenuItem dismissLocationTrackingOnGestureItem; private MenuItem dismissBearingTrackingOnGestureItem; @@ -51,7 +65,55 @@ public class MyLocationTrackingModeActivity extends AppCompatActivity implements protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my_location_tracking); + setupToolbar(); + + mapView = (MapView) findViewById(R.id.mapView); + mapView.onCreate(savedInstanceState); + mapView.getMapAsync(this); + } + + @Override + public void onMapReady(MapboxMap mapboxMap) { + MyLocationTrackingModeActivity.this.mapboxMap = mapboxMap; + lostApiClient = new LostApiClient.Builder(this).addConnectionCallbacks(this).build(); + lostApiClient.connect(); + } + + @Override + public void onConnected() { + LocationRequest request = LocationRequest.create() + .setPriority(LocationRequest.PRIORITY_LOW_POWER) + .setInterval(5000) + .setSmallestDisplacement(10); + + Location location = LocationServices.FusedLocationApi.getLastLocation(lostApiClient); + if (location != null) { + setInitialLocation(location, 15); + } + LocationServices.FusedLocationApi.requestLocationUpdates(lostApiClient, request, this); + } + + @Override + public void onConnectionSuspended() { + } + + @Override + public void onLocationChanged(Location location) { + Timber.e("Location changed %s", location); + if (firstRun) { + setInitialLocation(location, 16); + } + } + + private void setInitialLocation(Location location, double zoom) { + mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(location), zoom)); + mapboxMap.setMyLocationEnabled(true); + setupSpinners(mapboxMap); + firstRun = false; + } + + private void setupToolbar() { Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); @@ -60,72 +122,60 @@ protected void onCreate(final Bundle savedInstanceState) { actionBar.setDisplayShowTitleEnabled(false); actionBar.setDisplayHomeAsUpEnabled(true); actionBar.setDisplayShowHomeEnabled(true); - } - - locationSpinner = (Spinner) findViewById(R.id.spinner_location); - ArrayAdapter locationTrackingAdapter = ArrayAdapter.createFromResource( - actionBar.getThemedContext(), R.array.user_tracking_mode, android.R.layout.simple_spinner_item); - locationTrackingAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - locationSpinner.setAdapter(locationTrackingAdapter); - bearingSpinner = (Spinner) findViewById(R.id.spinner_bearing); - ArrayAdapter bearingTrackingAdapter = ArrayAdapter.createFromResource( - actionBar.getThemedContext(), R.array.user_bearing_mode, android.R.layout.simple_spinner_item); - bearingTrackingAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - bearingSpinner.setAdapter(bearingTrackingAdapter); + locationSpinner = (Spinner) findViewById(R.id.spinner_location); + ArrayAdapter locationTrackingAdapter = ArrayAdapter.createFromResource( + actionBar.getThemedContext(), R.array.user_tracking_mode, android.R.layout.simple_spinner_item); + locationTrackingAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + locationSpinner.setAdapter(locationTrackingAdapter); + + bearingSpinner = (Spinner) findViewById(R.id.spinner_bearing); + ArrayAdapter bearingTrackingAdapter = ArrayAdapter.createFromResource( + actionBar.getThemedContext(), R.array.user_bearing_mode, android.R.layout.simple_spinner_item); + bearingTrackingAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + bearingSpinner.setAdapter(bearingTrackingAdapter); + } + } - mapView = (MapView) findViewById(R.id.mapView); - mapView.onCreate(savedInstanceState); + private void setupSpinners(@NonNull MapboxMap mapboxMap) { + locationSpinner.setOnItemSelectedListener(MyLocationTrackingModeActivity.this); + bearingSpinner.setOnItemSelectedListener(MyLocationTrackingModeActivity.this); + setCheckBoxes(); - mapView.getMapAsync(new OnMapReadyCallback() { + mapboxMap.setOnMyLocationTrackingModeChangeListener(new MapboxMap.OnMyLocationTrackingModeChangeListener() { @Override - public void onMapReady(@NonNull MapboxMap mapboxMap) { - MyLocationTrackingModeActivity.this.mapboxMap = mapboxMap; - + public void onMyLocationTrackingModeChange(@MyLocationTracking.Mode int myLocationTrackingMode) { + locationSpinner.setOnItemSelectedListener(null); + switch (myLocationTrackingMode) { + case MyLocationTracking.TRACKING_NONE: + locationSpinner.setSelection(TRACKING_NONE_INDEX); + break; + case MyLocationTracking.TRACKING_FOLLOW: + locationSpinner.setSelection(TRACKING_FOLLOW_INDEX); + break; + } locationSpinner.setOnItemSelectedListener(MyLocationTrackingModeActivity.this); - bearingSpinner.setOnItemSelectedListener(MyLocationTrackingModeActivity.this); - setCheckBoxes(); - - mapboxMap.setOnMyLocationTrackingModeChangeListener(new MapboxMap.OnMyLocationTrackingModeChangeListener() { - @Override - public void onMyLocationTrackingModeChange(@MyLocationTracking.Mode int myLocationTrackingMode) { - locationSpinner.setOnItemSelectedListener(null); - switch (myLocationTrackingMode) { - case MyLocationTracking.TRACKING_NONE: - locationSpinner.setSelection(TRACKING_NONE_INDEX); - break; - case MyLocationTracking.TRACKING_FOLLOW: - locationSpinner.setSelection(TRACKING_FOLLOW_INDEX); - break; - } - locationSpinner.setOnItemSelectedListener(MyLocationTrackingModeActivity.this); - } - }); - - mapboxMap.setOnMyBearingTrackingModeChangeListener(new MapboxMap.OnMyBearingTrackingModeChangeListener() { - @Override - public void onMyBearingTrackingModeChange(@MyBearingTracking.Mode int myBearingTrackingMode) { - bearingSpinner.setOnItemSelectedListener(null); - switch (myBearingTrackingMode) { - case MyBearingTracking.NONE: - bearingSpinner.setSelection(BEARING_NONE_INDEX); - break; - - case MyBearingTracking.GPS: - bearingSpinner.setSelection(BEARING_GPS_INDEX); - break; - - case MyBearingTracking.COMPASS: - bearingSpinner.setSelection(BEARING_COMPASS_INDEX); - break; - } - bearingSpinner.setOnItemSelectedListener(MyLocationTrackingModeActivity.this); - } - }); - - if (savedInstanceState == null) { - mapboxMap.setMyLocationEnabled(true); + } + }); + + mapboxMap.setOnMyBearingTrackingModeChangeListener(new MapboxMap.OnMyBearingTrackingModeChangeListener() { + @Override + public void onMyBearingTrackingModeChange(@MyBearingTracking.Mode int myBearingTrackingMode) { + bearingSpinner.setOnItemSelectedListener(null); + switch (myBearingTrackingMode) { + case MyBearingTracking.NONE: + bearingSpinner.setSelection(BEARING_NONE_INDEX); + break; + + case MyBearingTracking.GPS: + bearingSpinner.setSelection(BEARING_GPS_INDEX); + break; + + case MyBearingTracking.COMPASS: + bearingSpinner.setSelection(BEARING_COMPASS_INDEX); + break; } + bearingSpinner.setOnItemSelectedListener(MyLocationTrackingModeActivity.this); } }); } @@ -186,6 +236,11 @@ protected void onPause() { @Override protected void onStop() { super.onStop(); + LocationServices.FusedLocationApi.removeLocationUpdates(lostApiClient, this); + if (lostApiClient.isConnected()) { + lostApiClient.unregisterConnectionCallbacks(this); + lostApiClient.disconnect(); + } mapView.onStop(); } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_tracking.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_tracking.xml index 95f084506bb..7236a944e90 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_tracking.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_tracking.xml @@ -45,6 +45,6 @@ app:mapbox_myLocationTintColor="@color/primary" app:mapbox_myLocationAccuracyTintColor="@color/primary" app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets" - app:mapbox_cameraZoom="15" /> + app:mapbox_cameraZoom="8" /> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_location_engine.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_location_engine.xml new file mode 100644 index 00000000000..dd7408df096 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_location_engine.xml @@ -0,0 +1,20 @@ + + + + + + + + + + \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml index 5b6cbb8c42d..74833105a41 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml @@ -151,6 +151,9 @@ Reset Enable rotate gestures Enable scroll gestures + Change to LOST location source + Change to mock location source + Reset location source to null Move diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java index 6ee5c157b99..e05190cd57a 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java @@ -5,6 +5,7 @@ import android.net.NetworkInfo; import com.mapbox.mapboxsdk.exceptions.MapboxConfigurationException; +import com.mapbox.mapboxsdk.location.LocationSource; import org.junit.Before; import org.junit.Test; @@ -24,11 +25,13 @@ public class MapboxTest { private Context context; private Context appContext; + private LocationSource locationSource; @Before public void before() { context = mock(Context.class); appContext = mock(Context.class); + locationSource = mock(LocationSource.class); when(context.getApplicationContext()).thenReturn(appContext); } @@ -80,7 +83,7 @@ public void testConnected() { } private void injectMapboxSingleton(String accessToken) { - Mapbox mapbox = new Mapbox(appContext, accessToken); + Mapbox mapbox = new Mapbox(appContext, accessToken, locationSource); try { Field field = Mapbox.class.getDeclaredField("INSTANCE"); field.setAccessible(true); diff --git a/platform/android/dependencies.gradle b/platform/android/dependencies.gradle index 5e80e344e4e..e71e0771046 100644 --- a/platform/android/dependencies.gradle +++ b/platform/android/dependencies.gradle @@ -21,8 +21,8 @@ ext { mapboxAndroidTelemetry : "com.mapbox.mapboxsdk:mapbox-android-telemetry:${mapboxServicesVersion}@aar", // mapzen lost - lost : 'com.mapzen.android:lost:3.0.0', - + lost : 'com.mapzen.android:lost:3.0.1-20170607.212149-4', + // unit test junit : 'junit:junit:4.12', mockito : 'org.mockito:mockito-core:2.2.27',