summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuardiola31337 <pablo.guardiola@mapbox.com>2019-06-18 11:23:11 -0400
committerGuardiola31337 <pablo.guardiola@mapbox.com>2019-06-18 11:23:11 -0400
commit66378e87748c8739d7f15e3bc94d885b528d247b (patch)
tree7eb75d00b5a80c5b0f90837854f175911afc323f
parent0b848619a51f7cab27cc1ddc0850537ec984c586 (diff)
downloadqtlocation-mapboxgl-upstream/pg-downstream-module.tar.gz
add component navigation activityupstream/pg-downstream-module
-rw-r--r--platform/android/MapboxGLDownstreamTestApp/build.gradle4
-rw-r--r--platform/android/MapboxGLDownstreamTestApp/src/main/AndroidManifest.xml3
-rw-r--r--platform/android/MapboxGLDownstreamTestApp/src/main/java/com/mapbox/mapboxsdk/downstream/testapp/ComponentNavigationActivity.java567
-rw-r--r--platform/android/MapboxGLDownstreamTestApp/src/main/java/com/mapbox/mapboxsdk/downstream/testapp/NavigationLauncherActivity.java11
-rw-r--r--platform/android/MapboxGLDownstreamTestApp/src/main/res/layout/activity_component_navigation.xml52
-rw-r--r--platform/android/MapboxGLDownstreamTestApp/src/main/res/values/colors.xml1
-rw-r--r--platform/android/MapboxGLDownstreamTestApp/src/main/res/values/dimens.xml5
-rw-r--r--platform/android/MapboxGLDownstreamTestApp/src/main/res/values/styles.xml30
8 files changed, 666 insertions, 7 deletions
diff --git a/platform/android/MapboxGLDownstreamTestApp/build.gradle b/platform/android/MapboxGLDownstreamTestApp/build.gradle
index eb6b786a32..f2e1fdbc23 100644
--- a/platform/android/MapboxGLDownstreamTestApp/build.gradle
+++ b/platform/android/MapboxGLDownstreamTestApp/build.gradle
@@ -44,11 +44,11 @@ android {
dependencies {
api(project(':MapboxGLAndroidSDK'))
- implementation("com.mapbox.mapboxsdk:mapbox-android-navigation-ui:0.37.0-20190424.195829-5") {
+ implementation("com.mapbox.mapboxsdk:mapbox-android-navigation-ui:0.40.0") {
exclude group: 'com.mapbox.mapboxsdk', module: 'mapbox-android-sdk'
exclude group: 'com.mapbox.mapboxsdk', module: 'mapbox-android-navigation'
}
- implementation "com.mapbox.mapboxsdk:mapbox-android-navigation:0.37.0-20190424.195804-5"
+ implementation "com.mapbox.mapboxsdk:mapbox-android-navigation:0.40.0"
// Butter Knife
implementation "com.jakewharton:butterknife:8.8.1"
diff --git a/platform/android/MapboxGLDownstreamTestApp/src/main/AndroidManifest.xml b/platform/android/MapboxGLDownstreamTestApp/src/main/AndroidManifest.xml
index 6dc3e80008..530cde6ea8 100644
--- a/platform/android/MapboxGLDownstreamTestApp/src/main/AndroidManifest.xml
+++ b/platform/android/MapboxGLDownstreamTestApp/src/main/AndroidManifest.xml
@@ -2,6 +2,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mapbox.mapboxsdk.downstream.testapp">
+ <uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
@@ -11,7 +12,7 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
- <activity android:name=".NavigationLauncherActivity">
+ <activity android:name=".ComponentNavigationActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
diff --git a/platform/android/MapboxGLDownstreamTestApp/src/main/java/com/mapbox/mapboxsdk/downstream/testapp/ComponentNavigationActivity.java b/platform/android/MapboxGLDownstreamTestApp/src/main/java/com/mapbox/mapboxsdk/downstream/testapp/ComponentNavigationActivity.java
new file mode 100644
index 0000000000..506fb904bd
--- /dev/null
+++ b/platform/android/MapboxGLDownstreamTestApp/src/main/java/com/mapbox/mapboxsdk/downstream/testapp/ComponentNavigationActivity.java
@@ -0,0 +1,567 @@
+package com.mapbox.mapboxsdk.downstream.testapp;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.res.Resources;
+import android.location.Location;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.constraint.ConstraintLayout;
+import android.support.design.widget.BaseTransientBottomBar;
+import android.support.design.widget.FloatingActionButton;
+import android.support.design.widget.Snackbar;
+import android.support.transition.TransitionManager;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+
+import com.mapbox.android.core.location.LocationEngine;
+import com.mapbox.android.core.location.LocationEngineCallback;
+import com.mapbox.android.core.location.LocationEngineProvider;
+import com.mapbox.android.core.location.LocationEngineRequest;
+import com.mapbox.android.core.location.LocationEngineResult;
+import com.mapbox.api.directions.v5.models.DirectionsResponse;
+import com.mapbox.api.directions.v5.models.DirectionsRoute;
+import com.mapbox.geojson.Point;
+import com.mapbox.mapboxsdk.Mapbox;
+import com.mapbox.mapboxsdk.camera.CameraPosition;
+import com.mapbox.mapboxsdk.camera.CameraUpdate;
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
+import com.mapbox.mapboxsdk.geometry.LatLng;
+import com.mapbox.mapboxsdk.geometry.LatLngBounds;
+import com.mapbox.mapboxsdk.location.modes.RenderMode;
+import com.mapbox.mapboxsdk.maps.MapView;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
+import com.mapbox.mapboxsdk.maps.Style;
+import com.mapbox.services.android.navigation.ui.v5.camera.DynamicCamera;
+import com.mapbox.services.android.navigation.ui.v5.camera.NavigationCamera;
+import com.mapbox.services.android.navigation.ui.v5.camera.NavigationCameraUpdate;
+import com.mapbox.services.android.navigation.ui.v5.instruction.InstructionView;
+import com.mapbox.services.android.navigation.ui.v5.map.NavigationMapboxMap;
+import com.mapbox.services.android.navigation.ui.v5.voice.NavigationSpeechPlayer;
+import com.mapbox.services.android.navigation.ui.v5.voice.SpeechAnnouncement;
+import com.mapbox.services.android.navigation.ui.v5.voice.SpeechPlayerProvider;
+import com.mapbox.services.android.navigation.ui.v5.voice.VoiceInstructionLoader;
+import com.mapbox.services.android.navigation.v5.milestone.Milestone;
+import com.mapbox.services.android.navigation.v5.milestone.MilestoneEventListener;
+import com.mapbox.services.android.navigation.v5.milestone.VoiceInstructionMilestone;
+import com.mapbox.services.android.navigation.v5.navigation.MapboxNavigation;
+import com.mapbox.services.android.navigation.v5.navigation.NavigationRoute;
+import com.mapbox.services.android.navigation.v5.offroute.OffRouteListener;
+import com.mapbox.services.android.navigation.v5.routeprogress.ProgressChangeListener;
+import com.mapbox.services.android.navigation.v5.routeprogress.RouteProgress;
+
+import java.io.File;
+import java.lang.ref.WeakReference;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import butterknife.OnClick;
+import okhttp3.Cache;
+import retrofit2.Call;
+import retrofit2.Callback;
+import retrofit2.Response;
+import timber.log.Timber;
+
+public class ComponentNavigationActivity extends AppCompatActivity implements OnMapReadyCallback,
+ MapboxMap.OnMapLongClickListener, ProgressChangeListener, MilestoneEventListener, OffRouteListener {
+
+ private static final int FIRST = 0;
+ private static final int ONE_HUNDRED_MILLISECONDS = 100;
+ private static final int BOTTOMSHEET_PADDING_MULTIPLIER = 4;
+ private static final int TWO_SECONDS_IN_MILLISECONDS = 2000;
+ private static final double BEARING_TOLERANCE = 90d;
+ private static final String LONG_PRESS_MAP_MESSAGE = "Long press the map to select a destination.";
+ private static final String SEARCHING_FOR_GPS_MESSAGE = "Searching for GPS...";
+ private static final String COMPONENT_NAVIGATION_INSTRUCTION_CACHE = "component-navigation-instruction-cache";
+ private static final long TEN_MEGABYTE_CACHE_SIZE = 10 * 1024 * 1024;
+ private static final int ZERO_PADDING = 0;
+ private static final double DEFAULT_ZOOM = 12.0;
+ private static final double DEFAULT_TILT = 0d;
+ private static final double DEFAULT_BEARING = 0d;
+ private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 1000;
+ private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = 500;
+
+ @BindView(R.id.componentNavigationLayout)
+ ConstraintLayout navigationLayout;
+
+ @BindView(R.id.mapView)
+ MapView mapView;
+
+ @BindView(R.id.instructionView)
+ InstructionView instructionView;
+
+ @BindView(R.id.startNavigationFab)
+ FloatingActionButton startNavigationFab;
+
+ @BindView(R.id.cancelNavigationFab)
+ FloatingActionButton cancelNavigationFab;
+
+ private final ComponentActivityLocationCallback callback = new ComponentActivityLocationCallback(this);
+ private LocationEngine locationEngine;
+ private MapboxNavigation navigation;
+ private NavigationSpeechPlayer speechPlayer;
+ private NavigationMapboxMap navigationMap;
+ private Location lastLocation;
+ private DirectionsRoute route;
+ private Point destination;
+ private MapState mapState;
+
+ private enum MapState {
+ INFO,
+ NAVIGATION
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ // For styling the InstructionView
+ setTheme(R.style.CustomInstructionView);
+ super.onCreate(savedInstanceState);
+ Mapbox.getInstance(getApplicationContext(), getString(R.string.mapbox_access_token));
+ setContentView(R.layout.activity_component_navigation);
+ ButterKnife.bind(this);
+ mapView.onCreate(savedInstanceState);
+
+ // Will call onMapReady
+ mapView.getMapAsync(this);
+ }
+
+ @Override
+ public void onMapReady(@NonNull MapboxMap mapboxMap) {
+ mapboxMap.setStyle(new Style.Builder().fromUrl(getString(R.string.navigation_guidance_day)), style -> {
+ mapState = MapState.INFO;
+ navigationMap = new NavigationMapboxMap(mapView, mapboxMap);
+
+ // For Location updates
+ initializeLocationEngine();
+
+ // For navigation logic / processing
+ initializeNavigation(mapboxMap);
+ navigationMap.updateCameraTrackingMode(NavigationCamera.NAVIGATION_TRACKING_MODE_NONE);
+ navigationMap.updateLocationLayerRenderMode(RenderMode.GPS);
+
+ // For voice instructions
+ initializeSpeechPlayer();
+ });
+ }
+
+ @Override
+ public boolean onMapLongClick(@NonNull LatLng point) {
+ // Only reverse geocode while we are not in navigation
+ if (mapState.equals(MapState.NAVIGATION)) {
+ return false;
+ }
+
+ // Fetch the route with this given point
+ destination = Point.fromLngLat(point.getLongitude(), point.getLatitude());
+ calculateRouteWith(destination, false);
+
+ // Clear any existing markers and add new one
+ navigationMap.clearMarkers();
+ navigationMap.addMarker(this, destination);
+
+ // Update camera to new destination
+ moveCameraToInclude(destination);
+ vibrate();
+ return false;
+ }
+
+ @OnClick(R.id.startNavigationFab)
+ public void onStartNavigationClick(FloatingActionButton floatingActionButton) {
+ // Transition to navigation state
+ mapState = MapState.NAVIGATION;
+
+ floatingActionButton.hide();
+ cancelNavigationFab.show();
+
+ // Show the InstructionView
+ TransitionManager.beginDelayedTransition(navigationLayout);
+ instructionView.setVisibility(View.VISIBLE);
+
+ // Start navigation
+ adjustMapPaddingForNavigation();
+ navigation.startNavigation(route);
+ addEventToHistoryFile("start_navigation");
+
+ // Location updates will be received from ProgressChangeListener
+ removeLocationEngineListener();
+
+ // TODO remove example usage
+ navigationMap.resetCameraPositionWith(NavigationCamera.NAVIGATION_TRACKING_MODE_GPS);
+ CameraUpdate cameraUpdate = cameraOverheadUpdate();
+ if (cameraUpdate != null) {
+ NavigationCameraUpdate navUpdate = new NavigationCameraUpdate(cameraUpdate);
+ navigationMap.retrieveCamera().update(navUpdate);
+ }
+ }
+
+ @OnClick(R.id.cancelNavigationFab)
+ public void onCancelNavigationClick(FloatingActionButton floatingActionButton) {
+ navigationMap.updateCameraTrackingMode(NavigationCamera.NAVIGATION_TRACKING_MODE_NONE);
+ // Transition to info state
+ mapState = MapState.INFO;
+
+ floatingActionButton.hide();
+
+ // Hide the InstructionView
+ TransitionManager.beginDelayedTransition(navigationLayout);
+ instructionView.setVisibility(View.INVISIBLE);
+
+ // Reset map camera and pitch
+ resetMapAfterNavigation();
+
+ // Add back regular location listener
+ addLocationEngineListener();
+ }
+
+ /*
+ * Navigation listeners
+ */
+
+ @Override
+ public void onProgressChange(Location location, RouteProgress routeProgress) {
+ // Cache "snapped" Locations for re-route Directions API requests
+ updateLocation(location);
+
+ // Update InstructionView data from RouteProgress
+ instructionView.updateDistanceWith(routeProgress);
+ }
+
+ @Override
+ public void onMilestoneEvent(RouteProgress routeProgress, String instruction, Milestone milestone) {
+ playAnnouncement(milestone);
+
+ // Update InstructionView banner instructions
+ instructionView.updateBannerInstructionsWith(milestone);
+ }
+
+ @Override
+ public void userOffRoute(Location location) {
+ calculateRouteWith(destination, true);
+ }
+
+ /*
+ * Activity lifecycle methods
+ */
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mapView.onResume();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mapView.onPause();
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ mapView.onStart();
+ if (navigationMap != null) {
+ navigationMap.onStart();
+ }
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ mapView.onSaveInstanceState(outState);
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ mapView.onStop();
+ if (navigationMap != null) {
+ navigationMap.onStop();
+ }
+ }
+
+ @Override
+ public void onLowMemory() {
+ super.onLowMemory();
+ mapView.onLowMemory();
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ mapView.onDestroy();
+
+ // Ensure proper shutdown of the SpeechPlayer
+ if (speechPlayer != null) {
+ speechPlayer.onDestroy();
+ }
+
+ // Prevent leaks
+ removeLocationEngineListener();
+
+ ((DynamicCamera) navigation.getCameraEngine()).clearMap();
+ // MapboxNavigation will shutdown the LocationEngine
+ navigation.onDestroy();
+ }
+
+ void checkFirstUpdate(Location location) {
+ if (lastLocation == null) {
+ moveCameraTo(location);
+ // Allow navigationMap clicks now that we have the current Location
+ navigationMap.retrieveMap().addOnMapLongClickListener(this);
+ showSnackbar(LONG_PRESS_MAP_MESSAGE, BaseTransientBottomBar.LENGTH_LONG);
+ }
+ }
+
+ void updateLocation(Location location) {
+ lastLocation = location;
+ navigationMap.updateLocation(location);
+ }
+
+ private void initializeSpeechPlayer() {
+ String english = Locale.US.getLanguage();
+ Cache cache = new Cache(new File(getApplication().getCacheDir(), COMPONENT_NAVIGATION_INSTRUCTION_CACHE),
+ TEN_MEGABYTE_CACHE_SIZE);
+ VoiceInstructionLoader voiceInstructionLoader = new VoiceInstructionLoader(getApplication(),
+ Mapbox.getAccessToken(), cache);
+ SpeechPlayerProvider speechPlayerProvider = new SpeechPlayerProvider(getApplication(), english, true,
+ voiceInstructionLoader);
+ speechPlayer = new NavigationSpeechPlayer(speechPlayerProvider);
+ }
+
+ @SuppressLint("MissingPermission")
+ private void initializeLocationEngine() {
+ locationEngine = LocationEngineProvider.getBestLocationEngine(getApplicationContext());
+ LocationEngineRequest request = buildEngineRequest();
+ locationEngine.requestLocationUpdates(request, callback, null);
+ showSnackbar(SEARCHING_FOR_GPS_MESSAGE, BaseTransientBottomBar.LENGTH_SHORT);
+ }
+
+ private void initializeNavigation(MapboxMap mapboxMap) {
+ navigation = new MapboxNavigation(this, Mapbox.getAccessToken());
+ navigation.setLocationEngine(locationEngine);
+ navigation.setCameraEngine(new DynamicCamera(mapboxMap));
+ navigation.addProgressChangeListener(this);
+ navigation.addMilestoneEventListener(this);
+ navigation.addOffRouteListener(this);
+ navigationMap.addProgressChangeListener(navigation);
+ }
+
+ private void showSnackbar(String text, int duration) {
+ Snackbar.make(navigationLayout, text, duration).show();
+ }
+
+ private void playAnnouncement(Milestone milestone) {
+ if (milestone instanceof VoiceInstructionMilestone) {
+ SpeechAnnouncement announcement = SpeechAnnouncement.builder()
+ .voiceInstructionMilestone((VoiceInstructionMilestone) milestone)
+ .build();
+ speechPlayer.play(announcement);
+ }
+ }
+
+ private void moveCameraTo(Location location) {
+ CameraPosition cameraPosition = buildCameraPositionFrom(location, location.getBearing());
+ navigationMap.retrieveMap().animateCamera(
+ CameraUpdateFactory.newCameraPosition(cameraPosition), TWO_SECONDS_IN_MILLISECONDS
+ );
+ }
+
+ private void moveCameraToInclude(Point destination) {
+ LatLng origin = new LatLng(lastLocation);
+ LatLngBounds bounds = new LatLngBounds.Builder()
+ .include(origin)
+ .include(new LatLng(destination.latitude(), destination.longitude()))
+ .build();
+ Resources resources = getResources();
+ int routeCameraPadding = (int) resources.getDimension(R.dimen.component_navigation_route_camera_padding);
+ int[] padding = {routeCameraPadding, routeCameraPadding, routeCameraPadding, routeCameraPadding};
+ CameraPosition cameraPosition = navigationMap.retrieveMap().getCameraForLatLngBounds(bounds, padding);
+ navigationMap.retrieveMap().animateCamera(
+ CameraUpdateFactory.newCameraPosition(cameraPosition), 6000
+ );
+ }
+
+ private void moveCameraOverhead() {
+ if (lastLocation == null) {
+ return;
+ }
+ CameraPosition cameraPosition = buildCameraPositionFrom(lastLocation, DEFAULT_BEARING);
+ navigationMap.retrieveMap().animateCamera(
+ CameraUpdateFactory.newCameraPosition(cameraPosition), TWO_SECONDS_IN_MILLISECONDS
+ );
+ }
+
+ @Nullable
+ private CameraUpdate cameraOverheadUpdate() {
+ if (lastLocation == null) {
+ return null;
+ }
+ CameraPosition cameraPosition = buildCameraPositionFrom(lastLocation, DEFAULT_BEARING);
+ return CameraUpdateFactory.newCameraPosition(cameraPosition);
+ }
+
+ @NonNull
+ private CameraPosition buildCameraPositionFrom(Location location, double bearing) {
+ return new CameraPosition.Builder()
+ .zoom(DEFAULT_ZOOM)
+ .target(new LatLng(location.getLatitude(), location.getLongitude()))
+ .bearing(bearing)
+ .tilt(DEFAULT_TILT)
+ .build();
+ }
+
+ private void adjustMapPaddingForNavigation() {
+ Resources resources = getResources();
+ int mapViewHeight = mapView.getHeight();
+ int bottomSheetHeight = (int) resources.getDimension(R.dimen.component_navigation_bottomsheet_height);
+ int topPadding = mapViewHeight - (bottomSheetHeight * BOTTOMSHEET_PADDING_MULTIPLIER);
+ navigationMap.retrieveMap().setPadding(ZERO_PADDING, topPadding, ZERO_PADDING, ZERO_PADDING);
+ }
+
+ private void resetMapAfterNavigation() {
+ navigationMap.removeRoute();
+ navigationMap.clearMarkers();
+ addEventToHistoryFile("cancel_navigation");
+ navigation.stopNavigation();
+ moveCameraOverhead();
+ }
+
+ private void removeLocationEngineListener() {
+ if (locationEngine != null) {
+ locationEngine.removeLocationUpdates(callback);
+ }
+ }
+
+ @SuppressLint("MissingPermission")
+ private void addLocationEngineListener() {
+ if (locationEngine != null) {
+ LocationEngineRequest request = buildEngineRequest();
+ locationEngine.requestLocationUpdates(request, callback, null);
+ }
+ }
+
+ private void calculateRouteWith(Point destination, boolean isOffRoute) {
+ Point origin = Point.fromLngLat(lastLocation.getLongitude(), lastLocation.getLatitude());
+ Double bearing = Float.valueOf(lastLocation.getBearing()).doubleValue();
+ NavigationRoute.builder(this)
+ .accessToken(Mapbox.getAccessToken())
+ .origin(origin, bearing, BEARING_TOLERANCE)
+ .destination(destination)
+ .build()
+ .getRoute(new Callback<DirectionsResponse>() {
+ @Override
+ public void onResponse(@NonNull Call<DirectionsResponse> call, @NonNull Response<DirectionsResponse> response) {
+ handleRoute(response, isOffRoute);
+ }
+
+ @Override
+ public void onFailure(@NonNull Call<DirectionsResponse> call, @NonNull Throwable throwable) {
+ Timber.e(throwable);
+ }
+ });
+ }
+
+ @OnClick(R.id.startNavigationFab)
+ public void quickStartNavigation() {
+ // Transition to navigation state
+ mapState = MapState.NAVIGATION;
+
+ cancelNavigationFab.show();
+
+ // Show the InstructionView
+ TransitionManager.beginDelayedTransition(navigationLayout);
+ instructionView.setVisibility(View.VISIBLE);
+
+ // Start navigation
+ adjustMapPaddingForNavigation();
+ navigation.startNavigation(route);
+ addEventToHistoryFile("start_navigation");
+
+ // Location updates will be received from ProgressChangeListener
+ removeLocationEngineListener();
+
+ // TODO remove example usage
+ navigationMap.resetCameraPositionWith(NavigationCamera.NAVIGATION_TRACKING_MODE_GPS);
+ CameraUpdate cameraUpdate = cameraOverheadUpdate();
+ if (cameraUpdate != null) {
+ NavigationCameraUpdate navUpdate = new NavigationCameraUpdate(cameraUpdate);
+ navigationMap.retrieveCamera().update(navUpdate);
+ }
+ }
+
+ private void handleRoute(Response<DirectionsResponse> response, boolean isOffRoute) {
+ List<DirectionsRoute> routes = response.body().routes();
+ if (!routes.isEmpty()) {
+ route = routes.get(FIRST);
+ navigationMap.drawRoute(route);
+ if (isOffRoute) {
+ navigation.startNavigation(route);
+ } else {
+ quickStartNavigation();
+ }
+ }
+ }
+
+ @SuppressLint("MissingPermission")
+ private void vibrate() {
+ Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ vibrator.vibrate(VibrationEffect.createOneShot(ONE_HUNDRED_MILLISECONDS, VibrationEffect.DEFAULT_AMPLITUDE));
+ } else {
+ vibrator.vibrate(ONE_HUNDRED_MILLISECONDS);
+ }
+ }
+
+ private void addEventToHistoryFile(String type) {
+ double secondsFromEpoch = new Date().getTime() / 1000.0;
+ navigation.addHistoryEvent(type, Double.toString(secondsFromEpoch));
+ }
+
+ @NonNull
+ private LocationEngineRequest buildEngineRequest() {
+ return new LocationEngineRequest.Builder(UPDATE_INTERVAL_IN_MILLISECONDS)
+ .setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY)
+ .setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS)
+ .build();
+ }
+
+ /*
+ * LocationEngine callback
+ */
+
+ private static class ComponentActivityLocationCallback implements LocationEngineCallback<LocationEngineResult> {
+
+ private final WeakReference<ComponentNavigationActivity> activityWeakReference;
+
+ ComponentActivityLocationCallback(ComponentNavigationActivity activity) {
+ this.activityWeakReference = new WeakReference<>(activity);
+ }
+
+ @Override
+ public void onSuccess(LocationEngineResult result) {
+ ComponentNavigationActivity activity = activityWeakReference.get();
+ if (activity != null) {
+ Location location = result.getLastLocation();
+ if (location == null) {
+ return;
+ }
+ activity.checkFirstUpdate(location);
+ activity.updateLocation(location);
+ }
+ }
+
+ @Override
+ public void onFailure(@NonNull Exception exception) {
+ Timber.e(exception);
+ }
+ }
+}
+
diff --git a/platform/android/MapboxGLDownstreamTestApp/src/main/java/com/mapbox/mapboxsdk/downstream/testapp/NavigationLauncherActivity.java b/platform/android/MapboxGLDownstreamTestApp/src/main/java/com/mapbox/mapboxsdk/downstream/testapp/NavigationLauncherActivity.java
index 8b067ac8dd..f4c69fc4db 100644
--- a/platform/android/MapboxGLDownstreamTestApp/src/main/java/com/mapbox/mapboxsdk/downstream/testapp/NavigationLauncherActivity.java
+++ b/platform/android/MapboxGLDownstreamTestApp/src/main/java/com/mapbox/mapboxsdk/downstream/testapp/NavigationLauncherActivity.java
@@ -358,10 +358,13 @@ public class NavigationLauncherActivity extends AppCompatActivity implements OnM
if (!offlineVersion.isEmpty()) {
optionsBuilder.offlineRoutingTilesVersion(offlineVersion);
}
- // TODO Testing merging previously sideloaded region
- optionsBuilder.offlineMapDatabasePath(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/" + "kingfarm_to_rockville.db");
- // TODO Testing merging previously downloaded region
- // optionsBuilder.offlineMapDatabasePath(getFilesDir().getPath() + "/" + "mbgl-offline.db");
+ // TODO Testing dynamic offline
+ /**
+ * File downloadDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
+ * String databaseFilePath = downloadDirectory + "/" + "kingfarm_to_rockville.db";
+ * String offlineStyleUrl = "mapbox://styles/mapbox/navigation-guidance-day-v4";
+ * optionsBuilder.offlineMapOptions(new MapOfflineOptions(databaseFilePath, offlineStyleUrl));
+ */
NavigationLauncher.startNavigation(this, optionsBuilder.build());
}
diff --git a/platform/android/MapboxGLDownstreamTestApp/src/main/res/layout/activity_component_navigation.xml b/platform/android/MapboxGLDownstreamTestApp/src/main/res/layout/activity_component_navigation.xml
new file mode 100644
index 0000000000..b45a775f52
--- /dev/null
+++ b/platform/android/MapboxGLDownstreamTestApp/src/main/res/layout/activity_component_navigation.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/componentNavigationLayout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <com.mapbox.mapboxsdk.maps.MapView
+ android:id="@+id/mapView"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"/>
+
+ <com.mapbox.services.android.navigation.ui.v5.instruction.InstructionView
+ android:id="@+id/instructionView"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="invisible"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"/>
+
+ <android.support.design.widget.FloatingActionButton
+ android:id="@+id/startNavigationFab"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="16dp"
+ android:layout_marginEnd="16dp"
+ android:layout_marginRight="16dp"
+ android:src="@drawable/ic_navigation"
+ android:visibility="invisible"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+ <android.support.design.widget.FloatingActionButton
+ android:id="@+id/cancelNavigationFab"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="16dp"
+ android:layout_marginEnd="16dp"
+ android:layout_marginRight="16dp"
+ android:src="@drawable/ic_close"
+ android:visibility="invisible"
+ app:backgroundTint="@color/white"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+</android.support.constraint.ConstraintLayout> \ No newline at end of file
diff --git a/platform/android/MapboxGLDownstreamTestApp/src/main/res/values/colors.xml b/platform/android/MapboxGLDownstreamTestApp/src/main/res/values/colors.xml
index 69b22338c6..85b272fb47 100644
--- a/platform/android/MapboxGLDownstreamTestApp/src/main/res/values/colors.xml
+++ b/platform/android/MapboxGLDownstreamTestApp/src/main/res/values/colors.xml
@@ -3,4 +3,5 @@
<color name="colorPrimary">#008577</color>
<color name="colorPrimaryDark">#00574B</color>
<color name="colorAccent">#D81B60</color>
+ <color name="white">#FFFFFF</color>
</resources>
diff --git a/platform/android/MapboxGLDownstreamTestApp/src/main/res/values/dimens.xml b/platform/android/MapboxGLDownstreamTestApp/src/main/res/values/dimens.xml
new file mode 100644
index 0000000000..8cba5b5ce1
--- /dev/null
+++ b/platform/android/MapboxGLDownstreamTestApp/src/main/res/values/dimens.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <dimen name="component_navigation_bottomsheet_height">96dp</dimen>
+ <dimen name="component_navigation_route_camera_padding">200dp</dimen>
+</resources> \ No newline at end of file
diff --git a/platform/android/MapboxGLDownstreamTestApp/src/main/res/values/styles.xml b/platform/android/MapboxGLDownstreamTestApp/src/main/res/values/styles.xml
index 5885930df6..59d574328e 100644
--- a/platform/android/MapboxGLDownstreamTestApp/src/main/res/values/styles.xml
+++ b/platform/android/MapboxGLDownstreamTestApp/src/main/res/values/styles.xml
@@ -8,4 +8,34 @@
<item name="colorAccent">@color/colorAccent</item>
</style>
+ <style name="CustomInstructionView" parent="Theme.AppCompat.Light.NoActionBar">
+ <item name="navigationViewPrimary">@color/mapbox_navigation_view_color_primary</item>
+ <item name="navigationViewSecondary">@color/mapbox_navigation_view_color_secondary</item>
+ <item name="navigationViewAccent">@color/mapbox_navigation_view_color_accent</item>
+ <item name="navigationViewPrimaryText">@color/mapbox_navigation_view_color_secondary</item>
+ <item name="navigationViewSecondaryText">@color/mapbox_navigation_view_color_accent_text</item>
+ <item name="navigationViewDivider">@color/mapbox_navigation_view_color_divider</item>
+
+ <item name="navigationViewListBackground">@color/mapbox_navigation_view_color_list_background</item>
+
+ <item name="navigationViewBannerBackground">@color/mapbox_navigation_view_color_banner_background</item>
+ <item name="navigationViewBannerPrimaryText">@color/mapbox_navigation_view_color_banner_primary_text</item>
+ <item name="navigationViewBannerSecondaryText">@color/mapbox_navigation_view_color_banner_secondary_text</item>
+ <item name="navigationViewBannerManeuverPrimary">@color/mapbox_navigation_view_color_banner_maneuver_primary</item>
+ <item name="navigationViewBannerManeuverSecondary">@color/mapbox_navigation_view_color_banner_maneuver_secondary</item>
+
+ <item name="navigationViewProgress">@color/mapbox_navigation_view_color_progress</item>
+ <item name="navigationViewProgressBackground">@color/mapbox_navigation_view_color_progress_background</item>
+
+ <item name="navigationViewRouteStyle">@style/NavigationMapRoute</item>
+
+ <item name="navigationViewLocationLayerStyle">@style/NavigationLocationLayerStyle</item>
+
+ <item name="navigationViewDestinationMarker">@drawable/map_marker_light</item>
+
+ <item name="navigationViewRouteOverviewDrawable">@drawable/ic_route_preview</item>
+
+ <item name="navigationViewMapStyle">@string/navigation_guidance_day</item>
+ </style>
+
</resources>