() {
+ @Override
+ public int compare(Section section, Section section1) {
+ return (section.firstPosition == section1.firstPosition)
+ ? 0
+ : ((section.firstPosition < section1.firstPosition) ? -1 : 1);
+ }
+ });
+
+ int offset = 0;
+ for (Section section : sections) {
+ section.sectionedPosition = section.firstPosition + offset;
+ this.sections.append(section.sectionedPosition, section);
+ ++offset;
+ }
+
+ notifyDataSetChanged();
+ }
+
+ int getConvertedPosition(int sectionedPosition) {
+ if (isSectionHeaderPosition(sectionedPosition)) {
+ return RecyclerView.NO_POSITION;
+ }
+
+ int offset = 0;
+ for (int i = 0; i < sections.size(); i++) {
+ if (sections.valueAt(i).sectionedPosition > sectionedPosition) {
+ break;
+ }
+ --offset;
+ }
+ return sectionedPosition + offset;
+ }
+
+ boolean isSectionHeaderPosition(int position) {
+ return sections.get(position) != null;
+ }
+
+
+ @Override
+ public long getItemId(int position) {
+ return isSectionHeaderPosition(position)
+ ? Integer.MAX_VALUE - sections.indexOfKey(position)
+ : adapter.getItemId(getConvertedPosition(position));
+ }
+
+ @Override
+ public int getItemCount() {
+ return (valid ? adapter.getItemCount() + sections.size() : 0);
+ }
+ }
+
+ private static class SectionViewHolder extends RecyclerView.ViewHolder {
+
+ private TextView title;
+
+ SectionViewHolder(@NonNull View view, @IdRes int textRes) {
+ super(view);
+ title = (TextView) view.findViewById(textRes);
+ title.setTypeface(FontCache.get("Roboto-Medium.ttf", view.getContext()));
+ }
+ }
+
+ private static class Section {
+ int firstPosition;
+ int sectionedPosition;
+ CharSequence title;
+
+ public Section(int firstPosition, CharSequence title) {
+ this.firstPosition = firstPosition;
+ this.title = title;
+ }
+
+ public CharSequence getTitle() {
+ return title;
+ }
+ }
+
+ private static class ItemClickSupport {
+ private final RecyclerView recyclerView;
+ private OnItemClickListener onItemClickListener;
+ private View.OnClickListener onClickListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (onItemClickListener != null) {
+ RecyclerView.ViewHolder holder = recyclerView.getChildViewHolder(view);
+ onItemClickListener.onItemClicked(recyclerView, holder.getAdapterPosition(), view);
+ }
+ }
+ };
+ private RecyclerView.OnChildAttachStateChangeListener attachListener
+ = new RecyclerView.OnChildAttachStateChangeListener() {
+ @Override
+ public void onChildViewAttachedToWindow(View view) {
+ if (onItemClickListener != null) {
+ view.setOnClickListener(onClickListener);
+ }
+ }
+
+ @Override
+ public void onChildViewDetachedFromWindow(View view) {
+
+ }
+ };
+
+ private ItemClickSupport(RecyclerView recyclerView) {
+ this.recyclerView = recyclerView;
+ this.recyclerView.setTag(R.id.item_click_support, this);
+ this.recyclerView.addOnChildAttachStateChangeListener(attachListener);
+ }
+
+ static ItemClickSupport addTo(RecyclerView view) {
+ ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
+ if (support == null) {
+ support = new ItemClickSupport(view);
+ }
+ return support;
+ }
+
+ ItemClickSupport setOnItemClickListener(OnItemClickListener listener) {
+ onItemClickListener = listener;
+ return this;
+ }
+
+ interface OnItemClickListener {
+
+ void onItemClicked(RecyclerView recyclerView, int position, View view);
+ }
+ }
+}
\ No newline at end of file
diff --git a/plugins/app/src/main/java/com/mapbox/mapboxsdk/plugins/testapp/activity/TrafficActivity.java b/plugins/app/src/main/java/com/mapbox/mapboxsdk/plugins/testapp/activity/TrafficActivity.java
new file mode 100644
index 000000000..edc786a68
--- /dev/null
+++ b/plugins/app/src/main/java/com/mapbox/mapboxsdk/plugins/testapp/activity/TrafficActivity.java
@@ -0,0 +1,134 @@
+package com.mapbox.mapboxsdk.plugins.testapp.activity;
+
+import android.os.Bundle;
+import android.support.design.widget.FloatingActionButton;
+import android.support.v7.app.AppCompatActivity;
+
+import com.mapbox.mapboxsdk.constants.Style;
+import com.mapbox.mapboxsdk.maps.MapView;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
+import com.mapbox.mapboxsdk.plugins.testapp.R;
+import com.mapbox.mapboxsdk.plugins.traffic.TrafficPlugin;
+
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import butterknife.OnClick;
+import timber.log.Timber;
+
+/**
+ * Activity showcasing TrafficPlugin plugin integration
+ */
+public class TrafficActivity extends AppCompatActivity implements OnMapReadyCallback {
+
+ @BindView(R.id.mapView)
+ MapView mapView;
+
+ @BindView(R.id.fabStyles)
+ FloatingActionButton stylesFab;
+
+ @BindView(R.id.fabTraffic)
+ FloatingActionButton trafficFab;
+
+ private MapboxMap mapboxMap;
+ private TrafficPlugin trafficPlugin;
+ private StyleCycle styleCycle = new StyleCycle();
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_traffic);
+ ButterKnife.bind(this);
+
+ mapView.setStyleUrl(styleCycle.getStyle());
+ mapView.onCreate(savedInstanceState);
+ mapView.getMapAsync(this);
+ }
+
+ @Override
+ public void onMapReady(MapboxMap mapboxMap) {
+ this.mapboxMap = mapboxMap;
+ this.trafficPlugin = new TrafficPlugin(mapView, mapboxMap);
+ }
+
+ @OnClick(R.id.fabTraffic)
+ public void onTrafficFabClick() {
+ if (mapboxMap != null) {
+ trafficPlugin.toggle();
+ Timber.e("Traffic plugin is enabled :%s", trafficPlugin.isEnabled());
+ }
+ }
+
+ @OnClick(R.id.fabStyles)
+ public void onStyleFabClick() {
+ if (mapboxMap != null) {
+ mapboxMap.setStyleUrl(styleCycle.getNextStyle());
+ }
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ mapView.onStart();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mapView.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mapView.onPause();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ mapView.onStop();
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ mapView.onSaveInstanceState(outState);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ mapView.onDestroy();
+ }
+
+ @Override
+ public void onLowMemory() {
+ super.onLowMemory();
+ mapView.onLowMemory();
+ }
+
+ private static class StyleCycle {
+ private static final String[] STYLES = new String[] {
+ Style.MAPBOX_STREETS,
+ Style.OUTDOORS,
+ Style.LIGHT,
+ Style.DARK,
+ Style.SATELLITE_STREETS
+ };
+
+ private int index;
+
+ private String getNextStyle() {
+ index++;
+ if (index == STYLES.length) {
+ index = 0;
+ }
+ return getStyle();
+ }
+
+ private String getStyle() {
+ return STYLES[index];
+ }
+ }
+}
\ No newline at end of file
diff --git a/plugins/app/src/main/res/drawable/ic_car.xml b/plugins/app/src/main/res/drawable/ic_car.xml
new file mode 100644
index 000000000..6d6337c3a
--- /dev/null
+++ b/plugins/app/src/main/res/drawable/ic_car.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/plugins/app/src/main/res/drawable/ic_layers.xml b/plugins/app/src/main/res/drawable/ic_layers.xml
new file mode 100644
index 000000000..84f5bb50a
--- /dev/null
+++ b/plugins/app/src/main/res/drawable/ic_layers.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/plugins/app/src/main/res/drawable/ic_layers_clear.xml b/plugins/app/src/main/res/drawable/ic_layers_clear.xml
new file mode 100644
index 000000000..ef2778257
--- /dev/null
+++ b/plugins/app/src/main/res/drawable/ic_layers_clear.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/plugins/app/src/main/res/drawable/line_divider.xml b/plugins/app/src/main/res/drawable/line_divider.xml
new file mode 100644
index 000000000..28258bddd
--- /dev/null
+++ b/plugins/app/src/main/res/drawable/line_divider.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/plugins/app/src/main/res/layout/activity_feature_overview.xml b/plugins/app/src/main/res/layout/activity_feature_overview.xml
index 3debee030..f917189a7 100644
--- a/plugins/app/src/main/res/layout/activity_feature_overview.xml
+++ b/plugins/app/src/main/res/layout/activity_feature_overview.xml
@@ -1,19 +1,14 @@
-
+ android:orientation="vertical">
-
+
-
+
\ No newline at end of file
diff --git a/plugins/app/src/main/res/layout/activity_traffic.xml b/plugins/app/src/main/res/layout/activity_traffic.xml
new file mode 100644
index 000000000..b603e9254
--- /dev/null
+++ b/plugins/app/src/main/res/layout/activity_traffic.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/plugins/app/src/main/res/layout/item_feature.xml b/plugins/app/src/main/res/layout/item_feature.xml
new file mode 100644
index 000000000..d2c493b2e
--- /dev/null
+++ b/plugins/app/src/main/res/layout/item_feature.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/plugins/app/src/main/res/layout/section_feature.xml b/plugins/app/src/main/res/layout/section_feature.xml
new file mode 100644
index 000000000..d1e1cb7b5
--- /dev/null
+++ b/plugins/app/src/main/res/layout/section_feature.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/plugins/app/src/main/res/values/ids.xml b/plugins/app/src/main/res/values/ids.xml
new file mode 100644
index 000000000..a96780447
--- /dev/null
+++ b/plugins/app/src/main/res/values/ids.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/plugins/app/src/main/res/values/strings.xml b/plugins/app/src/main/res/values/strings.xml
index 8193e8b8a..e7d8b5562 100644
--- a/plugins/app/src/main/res/values/strings.xml
+++ b/plugins/app/src/main/res/values/strings.xml
@@ -1,3 +1,17 @@
Mapbox Android Plugins
+
+
+ category
+ Navigation
+
+
+ Traffic Plugin
+
+
+ Add Traffic layers to any Mapbox basemap.
+
+
+ pk.eyJ1IjoiY2FtbWFjZSIsImEiOiJjaW9vbGtydnQwMDAwdmRrcWlpdDVoM3pjIn0.Oy_gHelWnV12kJxHQWV7XQ
+
diff --git a/plugins/app/src/test/java/com/mapbox/mapboxsdk/plugins/testapp/ExampleUnitTest.java b/plugins/app/src/test/java/com/mapbox/mapboxsdk/plugins/testapp/ExampleUnitTest.java
deleted file mode 100644
index 919eb744b..000000000
--- a/plugins/app/src/test/java/com/mapbox/mapboxsdk/plugins/testapp/ExampleUnitTest.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.mapbox.mapboxsdk.plugins.testapp;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * Example local unit test, which will execute on the development machine (host).
- *
- * @see Testing documentation
- */
-public class ExampleUnitTest {
- @Test
- public void addition_isCorrect() throws Exception {
- assertEquals(4, 2 + 2);
- }
-}
\ No newline at end of file
diff --git a/plugins/build.gradle b/plugins/build.gradle
index 184a0932b..5e0e0d57b 100644
--- a/plugins/build.gradle
+++ b/plugins/build.gradle
@@ -3,7 +3,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:2.3.0'
+ classpath 'com.android.tools.build:gradle:2.4.0-alpha5'
}
}
diff --git a/plugins/gradle/wrapper/gradle-wrapper.properties b/plugins/gradle/wrapper/gradle-wrapper.properties
index db8c6b0f8..950cb1862 100644
--- a/plugins/gradle/wrapper/gradle-wrapper.properties
+++ b/plugins/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Wed Apr 05 09:15:49 EDT 2017
+#Mon Apr 10 12:43:59 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
+distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
diff --git a/plugins/settings.gradle b/plugins/settings.gradle
index e7b4def49..d471af303 100644
--- a/plugins/settings.gradle
+++ b/plugins/settings.gradle
@@ -1 +1 @@
-include ':app'
+include ':app', ':traffic'
diff --git a/plugins/traffic/.gitignore b/plugins/traffic/.gitignore
new file mode 100644
index 000000000..796b96d1c
--- /dev/null
+++ b/plugins/traffic/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/plugins/traffic/build.gradle b/plugins/traffic/build.gradle
new file mode 100644
index 000000000..0baf3680b
--- /dev/null
+++ b/plugins/traffic/build.gradle
@@ -0,0 +1,19 @@
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion 25
+ buildToolsVersion "25.0.2"
+
+ defaultConfig {
+ minSdkVersion 15
+ targetSdkVersion 25
+ versionCode 1
+ versionName "0.1"
+ }
+}
+
+dependencies {
+ compile ('com.mapbox.mapboxsdk:mapbox-android-sdk:5.0.2@aar'){
+ transitive=true
+ }
+}
diff --git a/plugins/traffic/src/main/AndroidManifest.xml b/plugins/traffic/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..7987dc347
--- /dev/null
+++ b/plugins/traffic/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/plugins/traffic/src/main/java/com/mapbox/mapboxsdk/plugins/traffic/TrafficPlugin.java b/plugins/traffic/src/main/java/com/mapbox/mapboxsdk/plugins/traffic/TrafficPlugin.java
new file mode 100644
index 000000000..355625150
--- /dev/null
+++ b/plugins/traffic/src/main/java/com/mapbox/mapboxsdk/plugins/traffic/TrafficPlugin.java
@@ -0,0 +1,235 @@
+package com.mapbox.mapboxsdk.plugins.traffic;
+
+import android.graphics.Color;
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+
+import com.mapbox.mapboxsdk.maps.MapView;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.style.functions.CameraFunction;
+import com.mapbox.mapboxsdk.style.functions.Function;
+import com.mapbox.mapboxsdk.style.functions.stops.Stop;
+import com.mapbox.mapboxsdk.style.layers.Filter;
+import com.mapbox.mapboxsdk.style.layers.Layer;
+import com.mapbox.mapboxsdk.style.layers.LineLayer;
+import com.mapbox.mapboxsdk.style.sources.Source;
+import com.mapbox.mapboxsdk.style.sources.VectorSource;
+
+import java.util.List;
+
+import static com.mapbox.mapboxsdk.style.functions.Function.zoom;
+import static com.mapbox.mapboxsdk.style.functions.stops.Stop.stop;
+import static com.mapbox.mapboxsdk.style.functions.stops.Stops.categorical;
+import static com.mapbox.mapboxsdk.style.functions.stops.Stops.exponential;
+import static com.mapbox.mapboxsdk.style.layers.Filter.in;
+import static com.mapbox.mapboxsdk.style.layers.Filter.notIn;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillColor;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineColor;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineOffset;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineWidth;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility;
+
+/**
+ * The traffic plugin allows to add Mapbox Traffic v1 to the Mapbox Android SDK v5.0.2.
+ *
+ * Initialise this plugin in the {@link com.mapbox.mapboxsdk.maps.OnMapReadyCallback#onMapReady(MapboxMap)} and provide
+ * a valid instance of {@link MapView} and {@link MapboxMap}.
+ *
+ *
+ * Use {@link #toggle()} to switch state of this plugin to enable or disabled.
+ * Use {@link #isEnabled()} to validate if the plugin is active or not.
+ *
+ */
+public final class TrafficPlugin implements MapView.OnMapChangedListener {
+
+ private MapboxMap mapboxMap;
+ private boolean enabled;
+
+ /**
+ * Create a traffic plugin.
+ *
+ * @param mapView the MapView to apply the traffic plugin to
+ * @param mapboxMap the MapboxMap to apply traffic plugin with
+ */
+ public TrafficPlugin(@NonNull MapView mapView, @NonNull MapboxMap mapboxMap) {
+ this.mapboxMap = mapboxMap;
+ mapView.addOnMapChangedListener(this);
+ }
+
+ /**
+ * Returns true if the traffic plugin is currently enabled.
+ *
+ * @return true if enabled, false otherwise
+ */
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ /**
+ * Toggles the traffic plugin state.
+ *
+ * If the traffic plugin wasn't initialised yet, traffic source and layers will be added to the current map style.
+ * Else visibility will be toggled based on the current state.
+ *
+ */
+ public void toggle() {
+ enabled = !enabled;
+ updateState();
+ }
+
+ /**
+ * Called when a map change events occurs.
+ *
+ * Used to detect loading of a new style, if applicable reapply traffic source and layers.
+ *
+ *
+ * @param change the map change event that occurred
+ */
+ @Override
+ public void onMapChanged(int change) {
+ if (change == MapView.DID_FINISH_LOADING_STYLE && isEnabled()) {
+ updateState();
+ }
+ }
+
+ /**
+ * Update the state of the traffic plugin.
+ */
+ private void updateState() {
+ Source source = mapboxMap.getSource(SourceData.SOURCE_ID);
+ if (source == null) {
+ initSourceAndLayers();
+ return;
+ }
+ setVisibility(enabled);
+ }
+
+ /**
+ * Initialise the traffic source and layers
+ */
+ private void initSourceAndLayers() {
+ // source
+ VectorSource trafficSource = new VectorSource(SourceData.SOURCE_ID, SourceData.SOURCE_URL);
+ mapboxMap.addSource(trafficSource);
+
+ // functions
+ Function lineColor = TrafficFunction.getLineColorFunction(TrafficColor.BASE_GREEN, TrafficColor.BASE_YELLOW, TrafficColor.BASE_ORANGE, TrafficColor.BASE_RED);
+ Function lineColorCase = TrafficFunction.getLineColorFunction(TrafficColor.CASE_GREEN, TrafficColor.CASE_YELLOW, TrafficColor.CASE_ORANGE, TrafficColor.CASE_RED);
+ Function motorwayOffset = TrafficFunction.getOffsetFunction(stop(5, lineOffset(0.5f)), stop(13, lineOffset(3.0f)), stop(18, lineOffset(7.0f)));
+ Function otherOffset = TrafficFunction.getOffsetFunction(stop(7, lineOffset(0.3f)), stop(18, lineOffset(6.0f)), stop(22, lineOffset(100.0f)));
+ CameraFunction motorwayWidth = TrafficFunction.getWidthFunction(stop(7, lineWidth(1.5f)), stop(18, lineWidth(20.0f)));
+ CameraFunction motorwayCaseWidth = TrafficFunction.getWidthFunction(stop(7, lineWidth(3.0f)), stop(18, lineWidth(24.0f)));
+ CameraFunction otherWidth = TrafficFunction.getWidthFunction(stop(11, lineWidth(1.0f)), stop(14, lineWidth(2.0f)), stop(17, lineWidth(4.0f)), stop(22, lineWidth(30.0f)));
+ CameraFunction otherCaseWidth = TrafficFunction.getWidthFunction(stop(11, lineWidth(1.25f)), stop(14, lineWidth(2.5f)), stop(17, lineWidth(5.5f)), stop(22, lineWidth(34.0f)));
+
+ // layers
+ LineLayer motorWay = TrafficLayer.getLineLayer(MotorWay.BASE_LAYER_ID, lineColor, motorwayWidth, motorwayOffset, MotorWay.ZOOM_LEVEL, MotorWay.FILTER);
+ LineLayer motorwayCase = TrafficLayer.getLineLayer(MotorWay.CASE_LAYER_ID, lineColorCase, motorwayCaseWidth, motorwayOffset, MotorWay.ZOOM_LEVEL, MotorWay.FILTER);
+ LineLayer primary = TrafficLayer.getLineLayer(Primary.BASE_LAYER_ID, lineColor, otherWidth, otherOffset, Primary.ZOOM_LEVEL, Primary.FILTER);
+ LineLayer primaryCase = TrafficLayer.getLineLayer(Primary.CASE_LAYER_ID, lineColorCase, otherCaseWidth, otherOffset, Primary.ZOOM_LEVEL, Primary.FILTER);
+ LineLayer local = TrafficLayer.getLineLayer(Local.BASE_LAYER_ID, lineColor, otherWidth, otherOffset, Local.ZOOM_LEVEL, Local.FILTER);
+ LineLayer localCase = TrafficLayer.getLineLayer(Local.LOCAL_CASE_LAYER_ID, lineColorCase, otherCaseWidth, otherOffset, Local.ZOOM_LEVEL, Local.FILTER);
+
+ // // TODO: add above highest road label instead of bridge-motorway https://github.com/mapbox/mapbox-gl-native/issues/8663
+ mapboxMap.addLayerAbove(localCase, "bridge-motorway");
+ mapboxMap.addLayerAbove(local, localCase.getId());
+ mapboxMap.addLayerAbove(primaryCase, local.getId());
+ mapboxMap.addLayerAbove(primary, primaryCase.getId());
+ mapboxMap.addLayerAbove(motorwayCase, primary.getId());
+ mapboxMap.addLayerAbove(motorWay, motorwayCase.getId());
+ }
+
+ /**
+ * Toggles the visibility of the traffic layers.
+ *
+ * @param visible true for visible, false for none
+ */
+ private void setVisibility(boolean visible) {
+ List layers = mapboxMap.getLayers();
+ String id;
+ for (Layer layer : layers) {
+ id = layer.getId();
+ // TODO use sourceLayer filter instead
+ if (id.equals(MotorWay.BASE_LAYER_ID) || id.equals(MotorWay.CASE_LAYER_ID) || id.equals(Primary.BASE_LAYER_ID)
+ || id.equals(Primary.CASE_LAYER_ID) || id.equals(Primary.BASE_LAYER_ID) || id.equals(Primary.CASE_LAYER_ID)) {
+ layer.setProperties(visibility(visible ? "visible" : "none"));
+ }
+ }
+ }
+
+ private static class TrafficFunction {
+ private static Function getLineColorFunction(@ColorInt int low, @ColorInt int moderate, @ColorInt int heavy, @ColorInt int severe) {
+ return Function.property(
+ "congestion",
+ categorical(
+ stop("low", fillColor(low)),
+ stop("moderate", fillColor(moderate)),
+ stop("heavy", fillColor(heavy)),
+ stop("severe", fillColor(severe))
+ )
+ ).withDefaultValue(fillColor(Color.TRANSPARENT));
+ }
+
+ private static CameraFunction getOffsetFunction(Stop... stops) {
+ return zoom(exponential(stops).withBase(1.5f));
+ }
+
+ private static CameraFunction getWidthFunction(Stop... stops) {
+ return zoom(exponential(stops).withBase(1.5f));
+ }
+ }
+
+ private static class TrafficLayer {
+
+ private static LineLayer getLineLayer(String lineLayerId, Function lineColor, CameraFunction lineWidth, Function lineOffset, float minZoom, Filter.Statement statement) {
+ LineLayer lineLayer = new LineLayer(lineLayerId, SourceData.SOURCE_ID);
+ lineLayer.setSourceLayer(SourceData.SOURCE_LAYER);
+ lineLayer.setMinZoom(minZoom);
+ lineLayer.setProperties(
+ lineColor(lineColor),
+ lineWidth(lineWidth),
+ lineOffset(lineOffset)
+ );
+ lineLayer.setFilter(statement);
+ return lineLayer;
+ }
+ }
+
+ private static class SourceData {
+ private static final String SOURCE_ID = "traffic";
+ private static final String SOURCE_LAYER = "traffic";
+ private static final String SOURCE_URL = "mapbox://mapbox.mapbox-traffic-v1";
+ }
+
+ private static class MotorWay {
+ private static final String BASE_LAYER_ID = "traffic-motorway";
+ private static final String CASE_LAYER_ID = "traffic-motorway-case";
+ private static final float ZOOM_LEVEL = 5.0f;
+ private static final Filter.Statement FILTER = in("class", "motorway", "trunk");
+ }
+
+ private static class Primary {
+ private static final String BASE_LAYER_ID = "traffic-primary";
+ private static final String CASE_LAYER_ID = "traffic-primary-case";
+ private static final float ZOOM_LEVEL = 5.0f;
+ private static final Filter.Statement FILTER = notIn("class", "motorway", "trunk", "service", "street");
+ }
+
+ private static class Local {
+ private static final String BASE_LAYER_ID = "traffic-local";
+ private static final String LOCAL_CASE_LAYER_ID = "traffic-local-case";
+ private static final float ZOOM_LEVEL = 16.0f;
+ private static final Filter.Statement FILTER = in("class", "street");
+ }
+
+ private static class TrafficColor {
+ private static final int BASE_GREEN = Color.parseColor("#4CAF50");
+ private static final int CASE_GREEN = Color.parseColor("#388E3C");
+ private static final int BASE_YELLOW = Color.parseColor("#FFEB3B");
+ private static final int CASE_YELLOW = Color.parseColor("#FBC02D");
+ private static final int BASE_ORANGE = Color.parseColor("#FF9800");
+ private static final int CASE_ORANGE = Color.parseColor("#F57C00");
+ private static final int BASE_RED = Color.parseColor("#f44336");
+ private static final int CASE_RED = Color.parseColor("#D32F2F");
+ }
+}