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..a857a249db0 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 @@ -2,6 +2,7 @@ import android.app.Application; import android.content.Context; +import android.location.Location; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.support.annotation.NonNull; @@ -30,6 +31,7 @@ public final class Mapbox { private Context context; private String accessToken; private Boolean connected; + private LocationSource lostLocationSource; /** * Get an instance of Mapbox. @@ -45,8 +47,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 +57,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.lostLocationSource = locationSource; } /** @@ -128,4 +131,8 @@ public static synchronized Boolean isConnected() { NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); return (activeNetwork != null && activeNetwork.isConnected()); } + + public static LocationSource getDefaultLocationSource() { + return INSTANCE.lostLocationSource; + } } 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..130b40066aa 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 @@ -3,6 +3,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; @@ -40,9 +41,9 @@ public class LocationSource extends LocationEngine implements private WeakReference context; private LostApiClient lostApiClient; - private LocationSource(Context context) { + public LocationSource(Context context) { super(); - this.context = new WeakReference<>(context); + this.context = new WeakReference<>(context.getApplicationContext()); lostApiClient = new LostApiClient.Builder(this.context.get()) .addConnectionCallbacks(this) .build(); @@ -68,8 +69,11 @@ public static synchronized LocationEngine getLocationEngine(@NonNull Context con */ @Override public void activate() { - if (lostApiClient != null && !lostApiClient.isConnected()) { + Timber.e("LOCDEBUG %s activate - going to connect %s", hashCode(), !lostApiClient.isConnected()); + if (!lostApiClient.isConnected()) { lostApiClient.connect(); + }else{ + Timber.e("LOCDEBUG %s activate - NO connect", hashCode()); } } @@ -80,7 +84,8 @@ public void activate() { */ @Override public void deactivate() { - if (lostApiClient != null && lostApiClient.isConnected()) { + Timber.e("LOCDEBUG %s deactivate - going to disconnect %s", hashCode(), lostApiClient.isConnected()); + if (lostApiClient.isConnected()) { lostApiClient.disconnect(); } } @@ -101,6 +106,7 @@ public boolean isConnected() { */ @Override public void onConnected() { + Timber.e("LOCDEBUG %s onConnected", hashCode()); for (LocationEngineListener listener : locationListeners) { listener.onConnected(); } @@ -112,6 +118,7 @@ public void onConnected() { @Override public void onConnectionSuspended() { Timber.d("Connection suspended."); + Timber.e("LOCDEBUG %s ConnectedSuspended", hashCode()); } /** @@ -120,6 +127,7 @@ public void onConnectionSuspended() { * @return the last known location */ @Override + @Nullable public Location getLastLocation() { if (lostApiClient.isConnected() && PermissionsManager.areLocationPermissionsGranted(context.get())) { //noinspection MissingPermission @@ -153,6 +161,7 @@ public void requestLocationUpdates() { if (lostApiClient.isConnected() && PermissionsManager.areLocationPermissionsGranted(context.get())) { //noinspection MissingPermission + Timber.e("LOCDEBUG %s requestLocationUpdates with priority %s", hashCode(), priority); LocationServices.FusedLocationApi.requestLocationUpdates(lostApiClient, request, this); } } @@ -163,6 +172,7 @@ public void requestLocationUpdates() { @Override public void removeLocationUpdates() { if (lostApiClient.isConnected()) { + Timber.e("LOCDEBUG %s removeLocationUpdates", hashCode()); LocationServices.FusedLocationApi.removeLocationUpdates(lostApiClient, this); } } @@ -175,6 +185,7 @@ public void removeLocationUpdates() { @Override public void onLocationChanged(Location location) { for (LocationEngineListener listener : locationListeners) { + Timber.e("LOCDEBUG %s onLocationChanged %s", hashCode(), location); listener.onLocationChanged(location); } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java index d00da4c155d..7da12c11d69 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java @@ -32,6 +32,7 @@ import com.mapbox.mapboxsdk.annotations.MarkerViewManager; import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.constants.Style; +import com.mapbox.mapboxsdk.location.LocationSource; import com.mapbox.mapboxsdk.maps.widgets.CompassView; import com.mapbox.mapboxsdk.maps.widgets.MyLocationView; import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings; 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 3ddf4987abc..8c78b0fb160 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 @@ -1860,15 +1860,6 @@ public void setOnMyLocationChangeListener(@Nullable MapboxMap.OnMyLocationChange 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. * 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 e8cde1ef942..daff285ac11 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,6 +6,7 @@ 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; @@ -47,7 +48,7 @@ public final class TrackingSettings { } void initialise(MapboxMapOptions options) { - locationSource = LocationSource.getLocationEngine(myLocationView.getContext()); + locationSource = Mapbox.getDefaultLocationSource(); setMyLocationEnabled(options.getLocationEnabled()); } @@ -356,17 +357,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.getDefaultLocationSource(); + } 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 9e74c524d92..eeeccfe4fa5 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. */ @@ -147,6 +150,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; @@ -430,34 +437,27 @@ private void toggleGps(boolean enableGps, boolean isCustomLocationSource) { if (enableGps) { if (locationSource == null) { if (!isCustomLocationSource) { - locationSource = LocationSource.getLocationEngine(this.getContext()); + locationSource = Mapbox.getDefaultLocationSource(); } else { return; } } - // Set an initial location if one available - Location lastLocation = locationSource.getLastLocation(); - - if (lastLocation != null) { - setLocation(lastLocation); - } if (userLocationListener == null) { userLocationListener = new GpsLocationListener(this, locationSource); } locationSource.addLocationEngineListener(userLocationListener); - locationSource.activate(); - locationSource.setPriority(LocationEnginePriority.HIGH_ACCURACY); + locationSource.activate(); } else { if (locationSource == null) { return; } // Disable location and user dot location = null; - locationSource.removeLocationUpdates(); locationSource.removeLocationEngineListener(userLocationListener); + locationSource.removeLocationUpdates(); locationSource.deactivate(); } } @@ -571,14 +571,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 { @@ -596,8 +589,6 @@ public void onConnected() { MyLocationView locationView = userLocationView.get(); if (locationView != null) { LocationEngine locationEngine = locationSource.get(); - Location location = locationEngine.getLastLocation(); - locationView.setLocation(location); locationEngine.requestLocationUpdates(); } } @@ -641,6 +632,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; } 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..cf7ac2fc4ad 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,23 +123,27 @@ 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 onExplanationNeeded(List list) { + Snackbar.make( + findViewById(android.R.id.content), + TextUtils.join("",list.toArray()), + Snackbar.LENGTH_SHORT).show(); } @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - if (!isRuntimePermissionsRequired() || isPermissionAccepted(grantResults)) { - startFeature(features.get(requestCode)); - } else { + public void onPermissionResult(boolean b) { + if(b){ + startFeature(features.get(locationActivityInList)); + }else{ Snackbar.make( findViewById(android.R.id.content), "Can't open without accepting the location permission.", @@ -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..bb9b6d1015e 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,35 @@ 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 +39,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 b) { + enableLocation(b); } - 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..01deaf14e61 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,8 +2,12 @@ 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.location.LocationSource; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; @@ -16,22 +20,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 +40,7 @@ public void onMapReady(MapboxMap map) { @Override public void onClick(View view) { if (mapboxMap != null) { - toggleGps(!mapboxMap.isMyLocationEnabled()); + enableLocation(!mapboxMap.isMyLocationEnabled()); } } }); @@ -56,6 +56,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.getDefaultLocationSource()); + 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..9a363cc7496 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,52 @@ 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; /** - * 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; + + 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()); + } + } + }); + } - // 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 synchronized MockLocationEngine getInstance() { + if (INSTANCE == null) { + INSTANCE = new MockLocationEngine( + MockLocationEngine.createLocation(40.416913, -3.703861), + MockLocationEngine.createLocation(39.461643, -0.368041) + ); + } + return INSTANCE; + } + + 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 +55,6 @@ public void activate() { @Override public void deactivate() { - handler = null; } @Override @@ -51,44 +64,60 @@ 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; } } - 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.setRepeatCount(ValueAnimator.INFINITE); + 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) { + 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..a4efb3467a6 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 @@ -17,35 +17,36 @@ 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.LocationEngine; import com.mapbox.services.android.telemetry.location.LocationEngineListener; +import com.mapzen.android.lost.api.FusedLocationProviderApi; +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); mapboxMapOptions.myLocationBackgroundTintColor(Color.YELLOW); - 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.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..966ffc8fbbc 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 @@ -133,7 +133,7 @@ public void onLocationChanged(Location location) { protected void onStart() { super.onStart(); mapView.onStart(); - LocationSource.getLocationEngine(this).addLocationEngineListener(this); +// LocationSource.getLocationEngine(this).addLocationEngineListener(this); } @Override @@ -151,7 +151,7 @@ public void onPause() { @Override protected void onStop() { super.onStop(); - LocationSource.getLocationEngine(this).removeLocationEngineListener(this); + // 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..2845765a343 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,7 +1,9 @@ package com.mapbox.mapboxsdk.testapp.activity.userlocation; +import android.location.Location; import android.os.Bundle; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; @@ -13,8 +15,10 @@ 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; @@ -29,7 +33,8 @@ * using gesture configurations. *

*/ -public class MyLocationTrackingModeActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener { +public class MyLocationTrackingModeActivity extends AppCompatActivity implements MapboxMap.OnMyLocationChangeListener, + AdapterView.OnItemSelectedListener { public static final int TRACKING_NONE_INDEX = 0; public static final int TRACKING_FOLLOW_INDEX = 1; @@ -123,13 +128,23 @@ public void onMyBearingTrackingModeChange(@MyBearingTracking.Mode int myBearingT } }); + if (savedInstanceState == null) { mapboxMap.setMyLocationEnabled(true); } + mapboxMap.setOnMyLocationChangeListener(MyLocationTrackingModeActivity.this); } }); } + @Override + public void onMyLocationChange(@Nullable Location location) { + if (mapboxMap != null) { + mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom( + new LatLng(location.getLatitude(), location.getLongitude()), 13)); + } + } + @Override public void onItemSelected(AdapterView parent, View view, int position, long id) throws SecurityException { TrackingSettings trackingSettings = mapboxMap.getTrackingSettings(); @@ -186,6 +201,7 @@ protected void onPause() { @Override protected void onStop() { super.onStop(); + mapboxMap.setOnMyLocationChangeListener(null); mapView.onStop(); } 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..2f4695bec73 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/build.gradle b/platform/android/build.gradle index bc90896812f..b810622491c 100644 --- a/platform/android/build.gradle +++ b/platform/android/build.gradle @@ -1,9 +1,12 @@ buildscript { repositories { jcenter() + maven { + url 'https://maven.google.com' + } } dependencies { - classpath 'com.android.tools.build:gradle:2.3.1' + classpath 'com.android.tools.build:gradle:3.0.0-alpha2' classpath 'com.amazonaws:aws-devicefarm-gradle-plugin:1.2' classpath 'com.stanfy.spoon:spoon-gradle-plugin:1.2.1' } diff --git a/platform/android/dependencies.gradle b/platform/android/dependencies.gradle index 5e80e344e4e..92b24b3914c 100644 --- a/platform/android/dependencies.gradle +++ b/platform/android/dependencies.gradle @@ -22,7 +22,7 @@ ext { // mapzen lost lost : 'com.mapzen.android:lost:3.0.0', - + // unit test junit : 'junit:junit:4.12', mockito : 'org.mockito:mockito-core:2.2.27', diff --git a/platform/android/gradle/wrapper/gradle-wrapper.properties b/platform/android/gradle/wrapper/gradle-wrapper.properties index 1d35abd7b29..841dc8141ef 100644 --- a/platform/android/gradle/wrapper/gradle-wrapper.properties +++ b/platform/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Mar 03 10:22:19 EST 2017 +#Thu Jun 01 09:38:57 CEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip \ No newline at end of file +distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-milestone-1-all.zip