diff --git a/platform/android/MapboxGLDownstreamTestApp/.gitignore b/platform/android/MapboxGLDownstreamTestApp/.gitignore new file mode 100644 index 00000000000..796b96d1c40 --- /dev/null +++ b/platform/android/MapboxGLDownstreamTestApp/.gitignore @@ -0,0 +1 @@ +/build diff --git a/platform/android/MapboxGLDownstreamTestApp/build.gradle b/platform/android/MapboxGLDownstreamTestApp/build.gradle new file mode 100644 index 00000000000..9046bb27880 --- /dev/null +++ b/platform/android/MapboxGLDownstreamTestApp/build.gradle @@ -0,0 +1,60 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 28 + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + def getGitHash = { -> + try { + def stdout = new ByteArrayOutputStream() + exec { + commandLine 'git', 'rev-parse', '--short', 'HEAD' + standardOutput = stdout + } + return stdout.toString().trim() + } catch (Exception exception) { + return "" + } + } + + defaultConfig { + applicationId "com.mapbox.mapboxsdk.downstream.testapp" + minSdkVersion 14 + targetSdkVersion 28 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + buildConfigField "String", "GIT_HASH", "\"${getGitHash()}\"" + + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + +} + +dependencies { + api(project(':MapboxGLAndroidSDK')) + implementation("com.mapbox.mapboxsdk:mapbox-android-navigation-ui:0.34.0") { + exclude group: 'com.mapbox.mapboxsdk', module: 'mapbox-android-sdk' + } + + // Butter Knife + implementation "com.jakewharton:butterknife:8.8.1" + annotationProcessor "com.jakewharton:butterknife-compiler:8.8.1" + + implementation 'com.android.support:appcompat-v7:28.0.0' + implementation 'com.android.support.constraint:constraint-layout:1.1.3' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' +} diff --git a/platform/android/MapboxGLDownstreamTestApp/proguard-rules.pro b/platform/android/MapboxGLDownstreamTestApp/proguard-rules.pro new file mode 100644 index 00000000000..f1b424510da --- /dev/null +++ b/platform/android/MapboxGLDownstreamTestApp/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/platform/android/MapboxGLDownstreamTestApp/src/androidTest/java/com/mapbox/mapboxsdk/downstream/testapp/ExampleInstrumentedTest.java b/platform/android/MapboxGLDownstreamTestApp/src/androidTest/java/com/mapbox/mapboxsdk/downstream/testapp/ExampleInstrumentedTest.java new file mode 100644 index 00000000000..8fcdee1a988 --- /dev/null +++ b/platform/android/MapboxGLDownstreamTestApp/src/androidTest/java/com/mapbox/mapboxsdk/downstream/testapp/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.mapbox.mapboxsdk.downstream.testapp; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("com.mapbox.mapboxsdk.downstream.testapp", appContext.getPackageName()); + } +} diff --git a/platform/android/MapboxGLDownstreamTestApp/src/main/AndroidManifest.xml b/platform/android/MapboxGLDownstreamTestApp/src/main/AndroidManifest.xml new file mode 100644 index 00000000000..f62d77f83d8 --- /dev/null +++ b/platform/android/MapboxGLDownstreamTestApp/src/main/AndroidManifest.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file 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 new file mode 100644 index 00000000000..0c04625696f --- /dev/null +++ b/platform/android/MapboxGLDownstreamTestApp/src/main/java/com/mapbox/mapboxsdk/downstream/testapp/NavigationLauncherActivity.java @@ -0,0 +1,426 @@ +package com.mapbox.mapboxsdk.downstream.testapp; + +import android.content.Intent; +import android.content.SharedPreferences; +import android.location.Location; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.Snackbar; +import android.support.v7.app.AppCompatActivity; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.Button; +import android.widget.FrameLayout; +import android.widget.ProgressBar; +import android.widget.Toast; + +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.DirectionsCriteria; +import com.mapbox.api.directions.v5.models.DirectionsResponse; +import com.mapbox.api.directions.v5.models.DirectionsRoute; +import com.mapbox.core.constants.Constants; +import com.mapbox.geojson.LineString; +import com.mapbox.geojson.Point; +import com.mapbox.mapboxsdk.Mapbox; +import com.mapbox.mapboxsdk.annotations.Marker; +import com.mapbox.mapboxsdk.annotations.MarkerOptions; +import com.mapbox.mapboxsdk.camera.CameraPosition; +import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; +import com.mapbox.mapboxsdk.exceptions.InvalidLatLngBoundsException; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.geometry.LatLngBounds; +import com.mapbox.mapboxsdk.location.LocationComponent; +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.NavigationLauncher; +import com.mapbox.services.android.navigation.ui.v5.NavigationLauncherOptions; +import com.mapbox.services.android.navigation.ui.v5.route.NavigationMapRoute; +import com.mapbox.services.android.navigation.ui.v5.route.OnRouteSelectionChangeListener; +import com.mapbox.services.android.navigation.v5.navigation.NavigationRoute; +import com.mapbox.services.android.navigation.v5.utils.LocaleUtils; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import retrofit2.Call; +import retrofit2.Response; +import timber.log.Timber; + +public class NavigationLauncherActivity extends AppCompatActivity implements OnMapReadyCallback, + MapboxMap.OnMapLongClickListener, OnRouteSelectionChangeListener { + + private static final int CAMERA_ANIMATION_DURATION = 1000; + private static final int DEFAULT_CAMERA_ZOOM = 16; + private static final int CHANGE_SETTING_REQUEST_CODE = 1; + private static final int INITIAL_ZOOM = 16; + private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 1000; + private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = 500; + + private final NavigationLauncherLocationCallback callback = new NavigationLauncherLocationCallback(this); + private LocationEngine locationEngine; + private NavigationMapRoute mapRoute; + private MapboxMap mapboxMap; + private Marker currentMarker; + private Point currentLocation; + private Point destination; + private DirectionsRoute route; + private LocaleUtils localeUtils; + private boolean locationFound; + + @BindView(R.id.mapView) + MapView mapView; + @BindView(R.id.launch_route_btn) + Button launchRouteBtn; + @BindView(R.id.loading) + ProgressBar loading; + @BindView(R.id.launch_btn_frame) + FrameLayout launchBtnFrame; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Mapbox.getInstance(getApplicationContext(), getString(R.string.mapbox_access_token)); + setContentView(R.layout.activity_navigation_launcher); + ButterKnife.bind(this); + mapView.onCreate(savedInstanceState); + mapView.getMapAsync(this); + localeUtils = new LocaleUtils(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.navigation_view_activity_menu, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.settings: + showSettings(); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == CHANGE_SETTING_REQUEST_CODE && resultCode == RESULT_OK) { + boolean shouldRefetch = data.getBooleanExtra(NavigationSettingsActivity.UNIT_TYPE_CHANGED, false) + || data.getBooleanExtra(NavigationSettingsActivity.LANGUAGE_CHANGED, false); + if (destination != null && shouldRefetch) { + fetchRoute(); + } + } + } + + @Override + protected void onStart() { + super.onStart(); + mapView.onStart(); + } + + @SuppressWarnings( {"MissingPermission"}) + @Override + public void onResume() { + super.onResume(); + mapView.onResume(); + if (locationEngine != null) { + locationEngine.requestLocationUpdates(buildEngineRequest(), callback, null); + } + } + + @Override + public void onPause() { + super.onPause(); + mapView.onPause(); + if (locationEngine != null) { + locationEngine.removeLocationUpdates(callback); + } + } + + @Override + public void onLowMemory() { + super.onLowMemory(); + mapView.onLowMemory(); + } + + @Override + protected void onStop() { + super.onStop(); + mapView.onStop(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + mapView.onDestroy(); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + mapView.onSaveInstanceState(outState); + } + + @OnClick(R.id.launch_route_btn) + public void onRouteLaunchClick() { + launchNavigationWithRoute(); + } + + @Override + public void onMapReady(MapboxMap mapboxMap) { + this.mapboxMap = mapboxMap; + mapboxMap.setStyle(Style.MAPBOX_STREETS, style -> { + mapboxMap.addOnMapLongClickListener(this); + initializeLocationEngine(); + initializeLocationComponent(style); + initializeMapRoute(); + }); + } + + @Override + public boolean onMapLongClick(@NonNull LatLng point) { + destination = Point.fromLngLat(point.getLongitude(), point.getLatitude()); + launchRouteBtn.setEnabled(false); + loading.setVisibility(View.VISIBLE); + setCurrentMarkerPosition(point); + if (currentLocation != null) { + fetchRoute(); + } + return false; + } + + @Override + public void onNewPrimaryRouteSelected(DirectionsRoute directionsRoute) { + route = directionsRoute; + } + + void updateCurrentLocation(Point currentLocation) { + this.currentLocation = currentLocation; + } + + void onLocationFound(Location location) { + if (!locationFound) { + animateCamera(new LatLng(location.getLatitude(), location.getLongitude())); + Snackbar.make(mapView, R.string.explanation_long_press_waypoint, Snackbar.LENGTH_LONG).show(); + locationFound = true; + hideLoading(); + } + } + + private void showSettings() { + startActivityForResult(new Intent(this, NavigationSettingsActivity.class), CHANGE_SETTING_REQUEST_CODE); + } + + @SuppressWarnings( {"MissingPermission"}) + private void initializeLocationEngine() { + locationEngine = LocationEngineProvider.getBestLocationEngine(getApplicationContext()); + LocationEngineRequest request = buildEngineRequest(); + locationEngine.requestLocationUpdates(request, callback, null); + locationEngine.getLastLocation(callback); + } + + @SuppressWarnings( {"MissingPermission"}) + private void initializeLocationComponent(Style style) { + LocationComponent locationComponent = mapboxMap.getLocationComponent(); + locationComponent.activateLocationComponent(this, style, locationEngine); + locationComponent.setLocationComponentEnabled(true); + locationComponent.setRenderMode(RenderMode.COMPASS); + } + + private void initializeMapRoute() { + mapRoute = new NavigationMapRoute(mapView, mapboxMap); + mapRoute.setOnRouteSelectionChangeListener(this); + } + + private void fetchRoute() { + NavigationRoute.Builder builder = NavigationRoute.builder(this) + .accessToken(Mapbox.getAccessToken()) + .origin(currentLocation) + .destination(destination) + .profile(getRouteProfileFromSharedPreferences()) + .alternatives(true); + setFieldsFromSharedPreferences(builder); + builder.build() + .getRoute(new SimplifiedCallback() { + @Override + public void onResponse(Call call, Response response) { + if (validRouteResponse(response)) { + hideLoading(); + route = response.body().routes().get(0); + if (route.distance() > 25d) { + launchRouteBtn.setEnabled(true); + mapRoute.addRoutes(response.body().routes()); + boundCameraToRoute(); + } else { + Snackbar.make(mapView, R.string.error_select_longer_route, Snackbar.LENGTH_SHORT).show(); + } + } + } + }); + loading.setVisibility(View.VISIBLE); + } + + private void setFieldsFromSharedPreferences(NavigationRoute.Builder builder) { + builder + .language(getLanguageFromSharedPreferences()) + .voiceUnits(getUnitTypeFromSharedPreferences()); + } + + private String getUnitTypeFromSharedPreferences() { + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); + String defaultUnitType = getString(R.string.default_unit_type); + String unitType = sharedPreferences.getString(getString(R.string.unit_type_key), defaultUnitType); + if (unitType.equals(defaultUnitType)) { + unitType = localeUtils.getUnitTypeForDeviceLocale(this); + } + + return unitType; + } + + private Locale getLanguageFromSharedPreferences() { + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); + String defaultLanguage = getString(R.string.default_locale); + String language = sharedPreferences.getString(getString(R.string.language_key), defaultLanguage); + if (language.equals(defaultLanguage)) { + return localeUtils.inferDeviceLocale(this); + } else { + return new Locale(language); + } + } + + private boolean getShouldSimulateRouteFromSharedPreferences() { + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); + return sharedPreferences.getBoolean(getString(R.string.simulate_route_key), false); + } + + private String getRouteProfileFromSharedPreferences() { + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); + return sharedPreferences.getString( + getString(R.string.route_profile_key), DirectionsCriteria.PROFILE_DRIVING_TRAFFIC + ); + } + + private void launchNavigationWithRoute() { + if (route == null) { + Snackbar.make(mapView, R.string.error_route_not_available, Snackbar.LENGTH_SHORT).show(); + return; + } + + NavigationLauncherOptions.Builder optionsBuilder = NavigationLauncherOptions.builder() + .shouldSimulateRoute(getShouldSimulateRouteFromSharedPreferences()); + CameraPosition initialPosition = new CameraPosition.Builder() + .target(new LatLng(currentLocation.latitude(), currentLocation.longitude())) + .zoom(INITIAL_ZOOM) + .build(); + optionsBuilder.initialMapCameraPosition(initialPosition); + optionsBuilder.directionsRoute(route); + NavigationLauncher.startNavigation(this, optionsBuilder.build()); + } + + private boolean validRouteResponse(Response response) { + return response.body() != null && !response.body().routes().isEmpty(); + } + + private void hideLoading() { + if (loading.getVisibility() == View.VISIBLE) { + loading.setVisibility(View.INVISIBLE); + } + } + + public void boundCameraToRoute() { + if (route != null) { + List routeCoords = LineString.fromPolyline(route.geometry(), + Constants.PRECISION_6).coordinates(); + List bboxPoints = new ArrayList<>(); + for (Point point : routeCoords) { + bboxPoints.add(new LatLng(point.latitude(), point.longitude())); + } + if (bboxPoints.size() > 1) { + try { + LatLngBounds bounds = new LatLngBounds.Builder().includes(bboxPoints).build(); + // left, top, right, bottom + int topPadding = launchBtnFrame.getHeight() * 2; + animateCameraBbox(bounds, CAMERA_ANIMATION_DURATION, new int[] {50, topPadding, 50, 100}); + } catch (InvalidLatLngBoundsException exception) { + Toast.makeText(this, R.string.error_valid_route_not_found, Toast.LENGTH_SHORT).show(); + } + } + } + } + + private void animateCameraBbox(LatLngBounds bounds, int animationTime, int[] padding) { + CameraPosition position = mapboxMap.getCameraForLatLngBounds(bounds, padding); + mapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(position), animationTime); + } + + private void animateCamera(LatLng point) { + mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(point, DEFAULT_CAMERA_ZOOM), CAMERA_ANIMATION_DURATION); + } + + private void setCurrentMarkerPosition(LatLng position) { + if (position != null) { + if (currentMarker == null) { + MarkerOptions markerViewOptions = new MarkerOptions() + .position(position); + currentMarker = mapboxMap.addMarker(markerViewOptions); + } else { + currentMarker.setPosition(position); + } + } + } + + @NonNull + private LocationEngineRequest buildEngineRequest() { + return new LocationEngineRequest.Builder(UPDATE_INTERVAL_IN_MILLISECONDS) + .setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY) + .setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS) + .build(); + } + + private static class NavigationLauncherLocationCallback implements LocationEngineCallback { + + private final WeakReference activityWeakReference; + + NavigationLauncherLocationCallback(NavigationLauncherActivity activity) { + this.activityWeakReference = new WeakReference<>(activity); + } + + @Override + public void onSuccess(LocationEngineResult result) { + NavigationLauncherActivity activity = activityWeakReference.get(); + if (activity != null) { + Location location = result.getLastLocation(); + if (location == null) { + return; + } + activity.updateCurrentLocation(Point.fromLngLat(location.getLongitude(), location.getLatitude())); + activity.onLocationFound(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/NavigationSettingsActivity.java b/platform/android/MapboxGLDownstreamTestApp/src/main/java/com/mapbox/mapboxsdk/downstream/testapp/NavigationSettingsActivity.java new file mode 100644 index 00000000000..1441f367f52 --- /dev/null +++ b/platform/android/MapboxGLDownstreamTestApp/src/main/java/com/mapbox/mapboxsdk/downstream/testapp/NavigationSettingsActivity.java @@ -0,0 +1,94 @@ +package com.mapbox.mapboxsdk.downstream.testapp; + +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.os.Environment; +import android.preference.ListPreference; +import android.preference.PreferenceActivity; +import android.preference.PreferenceFragment; +import android.preference.PreferenceManager; +import android.support.annotation.NonNull; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class NavigationSettingsActivity extends PreferenceActivity { + + public static final String UNIT_TYPE_CHANGED = "unit_type_changed"; + public static final String LANGUAGE_CHANGED = "language_changed"; + public static final String OFFLINE_CHANGED = "offline_changed"; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + SharedPreferences.OnSharedPreferenceChangeListener listener = (sharedPreferences, key) -> { + Intent resultIntent = new Intent(); + resultIntent.putExtra(UNIT_TYPE_CHANGED, key.equals(getString(R.string.unit_type_key))); + resultIntent.putExtra(LANGUAGE_CHANGED, key.equals(getString(R.string.language_key))); + resultIntent.putExtra(OFFLINE_CHANGED, key.equals(getString(R.string.offline_version_key))); + setResult(RESULT_OK, resultIntent); + }; + + PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(listener); + getFragmentManager().beginTransaction().replace( + android.R.id.content, new NavigationViewPreferenceFragment() + ).commit(); + } + + @Override + protected boolean isValidFragment(String fragmentName) { + return super.isValidFragment(fragmentName); + } + + public static class NavigationViewPreferenceFragment extends PreferenceFragment { + + @Override + public void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.fragment_navigation_preferences); + String gitHashTitle = String.format("Last Commit Hash: %s", BuildConfig.GIT_HASH); + findPreference(getString(R.string.git_hash_key)).setTitle(gitHashTitle); + } + + @Override + public void onResume() { + super.onResume(); + + getOfflineVersions(); + PreferenceManager.setDefaultValues(getActivity(), R.xml.fragment_navigation_preferences, false); + } + + private void getOfflineVersions() { + File file = new File(Environment.getExternalStoragePublicDirectory("Offline"), "tiles"); + if (!file.exists()) { + file.mkdirs(); + } + + ListPreference offlineVersions = (ListPreference) findPreference(getString(R.string.offline_version_key)); + List list = buildFileList(file); + if (!list.isEmpty()) { + String[] entries = list.toArray(new String[list.size() - 1]); + offlineVersions.setEntries(entries); + offlineVersions.setEntryValues(entries); + offlineVersions.setEnabled(true); + } else { + offlineVersions.setEnabled(false); + } + } + + @NonNull + private List buildFileList(File file) { + List list; + if (file.list() != null && file.list().length != 0) { + list = new ArrayList<>(Arrays.asList(file.list())); + } else { + list = new ArrayList<>(); + } + return list; + } + } +} diff --git a/platform/android/MapboxGLDownstreamTestApp/src/main/java/com/mapbox/mapboxsdk/downstream/testapp/SimplifiedCallback.java b/platform/android/MapboxGLDownstreamTestApp/src/main/java/com/mapbox/mapboxsdk/downstream/testapp/SimplifiedCallback.java new file mode 100644 index 00000000000..95019b45699 --- /dev/null +++ b/platform/android/MapboxGLDownstreamTestApp/src/main/java/com/mapbox/mapboxsdk/downstream/testapp/SimplifiedCallback.java @@ -0,0 +1,18 @@ +package com.mapbox.mapboxsdk.downstream.testapp; + +import com.mapbox.api.directions.v5.models.DirectionsResponse; + +import retrofit2.Call; +import retrofit2.Callback; +import timber.log.Timber; + +/** + * Helper class to reduce redundant logging code when no other action is taken in onFailure + */ +public abstract class SimplifiedCallback implements Callback { + @Override + public void onFailure(Call call, Throwable throwable) { + Timber.e(throwable, throwable.getMessage()); + } +} + diff --git a/platform/android/MapboxGLDownstreamTestApp/src/main/res/drawable-v24/ic_launcher_foreground.xml b/platform/android/MapboxGLDownstreamTestApp/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 00000000000..485bbd377e2 --- /dev/null +++ b/platform/android/MapboxGLDownstreamTestApp/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/platform/android/MapboxGLDownstreamTestApp/src/main/res/drawable/demo_switch_background.xml b/platform/android/MapboxGLDownstreamTestApp/src/main/res/drawable/demo_switch_background.xml new file mode 100644 index 00000000000..a5ceeec08b6 --- /dev/null +++ b/platform/android/MapboxGLDownstreamTestApp/src/main/res/drawable/demo_switch_background.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/platform/android/MapboxGLDownstreamTestApp/src/main/res/drawable/ic_launcher_background.xml b/platform/android/MapboxGLDownstreamTestApp/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 00000000000..7ca09099aa5 --- /dev/null +++ b/platform/android/MapboxGLDownstreamTestApp/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/platform/android/MapboxGLDownstreamTestApp/src/main/res/drawable/ic_settings.xml b/platform/android/MapboxGLDownstreamTestApp/src/main/res/drawable/ic_settings.xml new file mode 100644 index 00000000000..f98df97aec4 --- /dev/null +++ b/platform/android/MapboxGLDownstreamTestApp/src/main/res/drawable/ic_settings.xml @@ -0,0 +1,5 @@ + + + diff --git a/platform/android/MapboxGLDownstreamTestApp/src/main/res/layout/activity_navigation_launcher.xml b/platform/android/MapboxGLDownstreamTestApp/src/main/res/layout/activity_navigation_launcher.xml new file mode 100644 index 00000000000..94d2f1bec7b --- /dev/null +++ b/platform/android/MapboxGLDownstreamTestApp/src/main/res/layout/activity_navigation_launcher.xml @@ -0,0 +1,42 @@ + + + + + + + + + +