summaryrefslogtreecommitdiff
path: root/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions
diff options
context:
space:
mode:
Diffstat (limited to 'platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions')
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CameraFunction.java50
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CompositeFunction.java86
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/Function.java301
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/SourceFunction.java84
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/package-info.java6
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/CategoricalStops.java64
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/CompositeStops.java151
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/ExponentialStops.java97
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IdentityStops.java18
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IntervalStops.java58
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IterableStops.java52
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/Stop.java109
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/Stops.java97
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/package-info.java6
14 files changed, 1179 insertions, 0 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CameraFunction.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CameraFunction.java
new file mode 100644
index 0000000000..bb87fe8a39
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CameraFunction.java
@@ -0,0 +1,50 @@
+package com.mapbox.mapboxsdk.style.functions;
+
+import android.support.annotation.Keep;
+import android.support.annotation.NonNull;
+
+import com.mapbox.mapboxsdk.style.functions.stops.ExponentialStops;
+import com.mapbox.mapboxsdk.style.functions.stops.IntervalStops;
+import com.mapbox.mapboxsdk.style.functions.stops.Stop;
+import com.mapbox.mapboxsdk.style.functions.stops.Stops;
+
+/**
+ * Camera function. Functions that take camera properties as input (zoom for now)
+ * <p>
+ * Zoom functions allow the appearance of a map feature to change with map’s zoom level.
+ * Zoom functions can be used to create the illusion of depth and control data density.
+ * Each stop is an array with two elements: the first is a zoom level and the second is
+ * a function output value.
+ *
+ * @param <I> the input type
+ * @param <O> the output type
+ * @see Function#zoom
+ */
+public class CameraFunction<I extends Number, O> extends Function<I, O> {
+
+ /**
+ * Create an exponential camera function
+ *
+ * @param stops @see {@link com.mapbox.mapboxsdk.style.functions.stops.Stops#exponential(float, Stop[])}
+ */
+ CameraFunction(@NonNull ExponentialStops<I, O> stops) {
+ super(stops);
+ }
+
+ /**
+ * Create an interval camera function
+ *
+ * @param stops @see {@link com.mapbox.mapboxsdk.style.functions.stops.Stops#interval(Stop[])}
+ */
+ CameraFunction(@NonNull IntervalStops<I, O> stops) {
+ super(stops);
+ }
+
+ /**
+ * JNI constructor
+ */
+ @Keep
+ private CameraFunction(Stops<I, O> stops) {
+ super(stops);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CompositeFunction.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CompositeFunction.java
new file mode 100644
index 0000000000..1ed43580c4
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CompositeFunction.java
@@ -0,0 +1,86 @@
+package com.mapbox.mapboxsdk.style.functions;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import com.mapbox.mapboxsdk.style.functions.stops.CompositeStops;
+import com.mapbox.mapboxsdk.style.functions.stops.Stops;
+
+import java.util.Map;
+
+/**
+ * Composite functions combine {@link android.graphics.Camera} and {@link SourceFunction}s.
+ * <p>
+ * Composite functions allow the appearance of a map feature to change with both its
+ * properties and zoom. Each stop is an array with two elements, the first is an object
+ * with a property input value and a zoom, and the second is a function output value. Note
+ * that support for property functions is not yet complete.
+ *
+ * @param <Z> the zoom type (usually Float)
+ * @param <I> the input type (the feature property type)
+ * @param <O> the output type (the property type)
+ * @see Function#composite
+ */
+public class CompositeFunction<Z extends Number, I, O> extends Function<I, O> {
+
+ private final String property;
+ private O defaultValue;
+
+ CompositeFunction(@NonNull String property,
+ @NonNull CompositeStops<Z, I, O, ? extends Stops<I, O>> stops) {
+ this(null, property, stops);
+ }
+
+
+ /**
+ * JNI Constructor
+ */
+ private CompositeFunction(@Nullable O defaultValue, @NonNull String property,
+ @NonNull CompositeStops<Z, I, O, ? extends Stops<I, O>> stops) {
+ super(stops);
+ this.defaultValue = defaultValue;
+ this.property = property;
+ }
+
+ /**
+ * Set the default value
+ *
+ * @param defaultValue the default value to use when no other applies
+ * @return this (for chaining)
+ */
+ public CompositeFunction<Z, I, O> withDefaultValue(O defaultValue) {
+ this.defaultValue = defaultValue;
+ return this;
+ }
+
+ /**
+ * @return the defaultValue
+ */
+ @Nullable
+ public O getDefaultValue() {
+ return defaultValue;
+ }
+
+ /**
+ * INTERNAL USAGE ONLY
+ *
+ * @return the feature property name
+ */
+ public String getProperty() {
+ return property;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Map<String, Object> toValueObject() {
+ Map<String, Object> valueObject = super.toValueObject();
+ valueObject.put(PROPERTY_KEY, property);
+ if (defaultValue != null) {
+ valueObject.put(DEFAULT_VALUE_KEY, defaultValue);
+ }
+ return valueObject;
+ }
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/Function.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/Function.java
new file mode 100644
index 0000000000..8c5186b994
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/Function.java
@@ -0,0 +1,301 @@
+package com.mapbox.mapboxsdk.style.functions;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import com.mapbox.mapboxsdk.style.functions.stops.CategoricalStops;
+import com.mapbox.mapboxsdk.style.functions.stops.CompositeStops;
+import com.mapbox.mapboxsdk.style.functions.stops.ExponentialStops;
+import com.mapbox.mapboxsdk.style.functions.stops.IdentityStops;
+import com.mapbox.mapboxsdk.style.functions.stops.IntervalStops;
+import com.mapbox.mapboxsdk.style.functions.stops.Stop;
+import com.mapbox.mapboxsdk.style.functions.stops.Stops;
+
+import java.util.Map;
+
+import timber.log.Timber;
+
+/**
+ * Functions are used to change properties in relation to the state of the map.
+ * <p>
+ * The value for any layout or paint property may be specified as a function. Functions allow you to
+ * make the appearance of a map feature change with the current zoom level and/or the feature's properties.
+ *
+ * @param <I> the function's input type
+ * @param <O> the target property's value type. Make sure it matches.
+ * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#types-function">The style specification</a>
+ */
+public class Function<I, O> {
+
+ static final String PROPERTY_KEY = "property";
+ static final String DEFAULT_VALUE_KEY = "defaultValue";
+
+ /**
+ * Create an exponential {@link CameraFunction}
+ * <p>
+ * Zoom functions allow the appearance of a map feature to change with map’s zoom.
+ * Zoom functions can be used to create the illusion of depth and control data density.
+ * Each stop is an array with two elements, the first is a zoom and the second is a function output value.
+ *
+ * @param <Z> the zoom level type (Float, Integer)
+ * @param <O> the property type
+ * @param stops the stops implementation that define the function. @see {@link Stops#exponential(Stop[])}
+ * @return the {@link CameraFunction}
+ * @see CameraFunction
+ * @see ExponentialStops
+ * @see Stops#exponential(Stop[])
+ * @see Stops#exponential(Stop[])
+ * @see Stop#stop
+ */
+ public static <Z extends Number, O> CameraFunction<Z, O> zoom(@NonNull ExponentialStops<Z, O> stops) {
+ return new CameraFunction<>(stops);
+ }
+
+ /**
+ * Create an interval {@link CameraFunction}
+ * <p>
+ * Zoom functions allow the appearance of a map feature to change with map’s zoom.
+ * Zoom functions can be used to create the illusion of depth and control data density.
+ * Each stop is an array with two elements, the first is a zoom and the second is a function output value.
+ *
+ * @param <Z> the zoom level type (Float, Integer)
+ * @param <O> the property type
+ * @param stops the stops implementation that define the function. @see {@link Stops#interval(Stop[])}
+ * @return the {@link CameraFunction}
+ * @see CameraFunction
+ * @see IntervalStops
+ * @see Stops#interval(Stop[])
+ * @see Stop#stop
+ */
+ public static <Z extends Number, O> CameraFunction<Z, O> zoom(@NonNull IntervalStops<Z, O> stops) {
+ return new CameraFunction<>(stops);
+ }
+
+ /**
+ * Create an exponential {@link SourceFunction}
+ * <p>
+ * Source functions allow the appearance of a map feature to change with
+ * its properties. Source functions can be used to visually differentiate
+ * types of features within the same layer or create data visualizations.
+ * Each stop is an array with two elements, the first is a property input
+ * value and the second is a function output value. Note that support for
+ * property functions is not available across all properties and platforms
+ * at this time.
+ *
+ * @param property the feature property name
+ * @param stops the stops
+ * @param <I> the function input type
+ * @param <O> the function output type
+ * @return the {@link SourceFunction}
+ * @see SourceFunction
+ * @see ExponentialStops
+ * @see Stops#exponential(Stop[])
+ * @see Stop#stop
+ */
+ public static <I, O> SourceFunction<I, O> property(@NonNull String property, @NonNull ExponentialStops<I, O> stops) {
+ return new SourceFunction<>(property, stops);
+ }
+
+ /**
+ * Create an identity {@link SourceFunction}
+ * <p>
+ * Source functions allow the appearance of a map feature to change with
+ * its properties. Source functions can be used to visually differentiate
+ * types of features within the same layer or create data visualizations.
+ * Each stop is an array with two elements, the first is a property input
+ * value and the second is a function output value. Note that support for
+ * property functions is not available across all properties and platforms
+ * at this time.
+ *
+ * @param property the feature property name
+ * @param stops the stops
+ * @param <T> the function input/output type
+ * @return the {@link SourceFunction}
+ * @see SourceFunction
+ * @see IdentityStops
+ * @see Stops#identity()
+ * @see Stop#stop
+ */
+ public static <T> SourceFunction<T, T> property(@NonNull String property, @NonNull IdentityStops<T> stops) {
+ return new SourceFunction<>(property, stops);
+ }
+
+ /**
+ * Create an interval {@link SourceFunction}
+ * <p>
+ * Source functions allow the appearance of a map feature to change with
+ * its properties. Source functions can be used to visually differentiate
+ * types of features within the same layer or create data visualizations.
+ * Each stop is an array with two elements, the first is a property input
+ * value and the second is a function output value. Note that support for
+ * property functions is not available across all properties and platforms
+ * at this time.
+ *
+ * @param property the feature property name
+ * @param stops the stops
+ * @param <I> the function input type
+ * @param <O> the function output type
+ * @return the {@link SourceFunction}
+ * @see SourceFunction
+ * @see IntervalStops
+ * @see Stops#interval(Stop[])
+ * @see Stop#stop
+ */
+ public static <I, O> SourceFunction<I, O> property(@NonNull String property, @NonNull IntervalStops<I, O> stops) {
+ return new SourceFunction<>(property, stops);
+ }
+
+ /**
+ * Create an categorical {@link SourceFunction}
+ * <p>
+ * Source functions allow the appearance of a map feature to change with
+ * its properties. Source functions can be used to visually differentiate
+ * types of features within the same layer or create data visualizations.
+ * Each stop is an array with two elements, the first is a property input
+ * value and the second is a function output value. Note that support for
+ * property functions is not available across all properties and platforms
+ * at this time.
+ *
+ * @param property the feature property name
+ * @param stops the stops
+ * @param <I> the function input type
+ * @param <O> the function output type
+ * @return the {@link SourceFunction}
+ * @see SourceFunction
+ * @see CategoricalStops
+ * @see Stops#categorical(Stop[])
+ * @see Stop#stop
+ */
+ public static <I, O> SourceFunction<I, O> property(@NonNull String property, @NonNull CategoricalStops<I, O> stops) {
+ return new SourceFunction<>(property, stops);
+ }
+
+ /**
+ * Create a composite, categorical function.
+ * <p>
+ * Composite functions allow the appearance of a map feature to change with both its
+ * properties and zoom. Each stop is an array with two elements, the first is an object
+ * with a property input value and a zoom, and the second is a function output value. Note
+ * that support for property functions is not yet complete.
+ *
+ * @param property the feature property name for the source part of the function
+ * @param stops the stops
+ * @param <Z> the zoom function input type (Float usually)
+ * @param <I> the function input type for the source part of the function
+ * @param <O> the function output type
+ * @return the {@link CompositeFunction}
+ * @see CompositeFunction
+ * @see CategoricalStops
+ * @see Stops#categorical(Stop[])
+ * @see Stop#stop
+ */
+ public static <Z extends Number, I, O> CompositeFunction<Z, I, O> composite(
+ @NonNull String property,
+ @NonNull CategoricalStops<Stop.CompositeValue<Z, I>, O> stops) {
+
+ return new CompositeFunction<>(property, new CompositeStops<>(stops));
+ }
+
+ /**
+ * Create a composite, exponential function.
+ * <p>
+ * Composite functions allow the appearance of a map feature to change with both its
+ * properties and zoom. Each stop is an array with two elements, the first is an object
+ * with a property input value and a zoom, and the second is a function output value. Note
+ * that support for property functions is not yet complete.
+ *
+ * @param property the feature property name for the source part of the function
+ * @param stops the stops
+ * @param <Z> the zoom function input type (Float usually)
+ * @param <I> the function input type for the source part of the function
+ * @param <O> the function output type
+ * @return the {@link CompositeFunction}
+ * @see CompositeFunction
+ * @see ExponentialStops
+ * @see Stops#exponential(Stop[])
+ * @see Stop#stop
+ */
+ public static <Z extends Number, I, O> CompositeFunction<Z, I, O> composite(
+ @NonNull String property,
+ @NonNull ExponentialStops<Stop.CompositeValue<Z, I>, O> stops) {
+
+ return new CompositeFunction<>(property, new CompositeStops<>(stops));
+ }
+
+ /**
+ * Create a composite, interval function.
+ * <p>
+ * Composite functions allow the appearance of a map feature to change with both its
+ * properties and zoom. Each stop is an array with two elements, the first is an object
+ * with a property input value and a zoom, and the second is a function output value. Note
+ * that support for property functions is not yet complete.
+ *
+ * @param property the feature property name for the source part of the function
+ * @param stops the stops
+ * @param <Z> the zoom function input type (Float usually)
+ * @param <I> the function input type for the source part of the function
+ * @param <O> the function output type
+ * @return the {@link CompositeFunction}
+ * @see CompositeFunction
+ * @see IntervalStops
+ * @see Stops#interval(Stop[])
+ * @see Stop#stop
+ */
+ public static <Z extends Number, I, O> CompositeFunction<Z, I, O> composite(
+ @NonNull String property,
+ @NonNull IntervalStops<Stop.CompositeValue<Z, I>, O> stops) {
+
+ return new CompositeFunction<>(property, new CompositeStops<>(stops));
+ }
+
+ // Class definition //
+
+ private final Stops<I, O> stops;
+
+ /**
+ * JNI Cosntructor for implementation classes
+ *
+ * @param stops the stops
+ */
+ Function(@NonNull Stops stops) {
+ this.stops = stops;
+ }
+
+ /**
+ * @return the stops in this function
+ */
+ public Stops getStops() {
+ return stops;
+ }
+
+ /**
+ * Convenience method
+ *
+ * @param <S> the Stops implementation type
+ * @return the Stops implementation or null when the wrong type is specified
+ */
+ @Nullable
+ public <S extends Stops> S getStopsAs() {
+ try {
+ // noinspection unchecked
+ return (S) stops;
+ } catch (ClassCastException exception) {
+ Timber.e(String.format("Stops: %s is a different type: %s", stops.getClass(), exception));
+ return null;
+ }
+ }
+
+ /**
+ * INTERNAL USAGE ONLY
+ *
+ * @return a value object representation for core conversion
+ */
+ public Map<String, Object> toValueObject() {
+ return stops.toValueObject();
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s: %s", getClass().getSimpleName(), stops);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/SourceFunction.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/SourceFunction.java
new file mode 100644
index 0000000000..f0eed760a4
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/SourceFunction.java
@@ -0,0 +1,84 @@
+package com.mapbox.mapboxsdk.style.functions;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import com.mapbox.mapboxsdk.style.functions.stops.Stops;
+
+import java.util.Map;
+
+/**
+ * Source functions take Feature property names as input.
+ * <p>
+ * Source functions allow the appearance of a map feature to change with
+ * its properties. Source functions can be used to visually differentiate
+ * types of features within the same layer or create data visualizations.
+ * Each stop is an array with two elements, the first is a property input
+ * value and the second is a function output value. Note that support for
+ * property functions is not available across all properties and platforms
+ * at this time.
+ *
+ * @param <I> the input type
+ * @param <O> the output type
+ * @see Function#property
+ */
+public class SourceFunction<I, O> extends Function<I, O> {
+
+ private final String property;
+ private O defaultValue;
+
+ SourceFunction(@NonNull String property, @NonNull Stops<I, O> stops) {
+ this(null, property, stops);
+ }
+
+ /**
+ * JNI Constructor
+ */
+ private SourceFunction(@Nullable O defaultValue, @NonNull String property, @NonNull Stops<I, O> stops) {
+ super(stops);
+ this.property = property;
+ this.defaultValue = defaultValue;
+ }
+
+
+ /**
+ * INTERNAL USAGE ONLY
+ *
+ * @return The feature property name
+ */
+ public String getProperty() {
+ return property;
+ }
+
+ /**
+ * Set the default value
+ *
+ * @param defaultValue the default value to use when no other applies
+ * @return this (for chaining)
+ */
+ public SourceFunction<I, O> withDefaultValue(O defaultValue) {
+ this.defaultValue = defaultValue;
+ return this;
+ }
+
+ /**
+ * @return the defaultValue
+ */
+ @Nullable
+ public O getDefaultValue() {
+ return defaultValue;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Map<String, Object> toValueObject() {
+ Map<String, Object> valueObject = super.toValueObject();
+ valueObject.put(PROPERTY_KEY, property);
+ if (defaultValue != null) {
+ valueObject.put(DEFAULT_VALUE_KEY, defaultValue);
+ }
+ return valueObject;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/package-info.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/package-info.java
new file mode 100644
index 0000000000..6979676c9e
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * Contains the Mapbox Maps Android Style Function API classes.
+ *
+ * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#types-function">The style specification</a>
+ */
+package com.mapbox.mapboxsdk.style.functions;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/CategoricalStops.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/CategoricalStops.java
new file mode 100644
index 0000000000..f9b2929350
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/CategoricalStops.java
@@ -0,0 +1,64 @@
+package com.mapbox.mapboxsdk.style.functions.stops;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Size;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * {@link Stops} implementation for categorical functions
+ *
+ * @param <I> the {@link Stop} input type
+ * @param <O> the {@link Stop} output type
+ */
+public class CategoricalStops<I, O> extends IterableStops<I, O, Stop<I, O>> {
+
+ private final Stop<I, O>[] stops;
+
+ /**
+ * Create a categorical {@link Stops} implementation. Use through {@link Stops#categorical(Stop[])}
+ *
+ * @param stops the stops
+ */
+ @SafeVarargs
+ public CategoricalStops(@NonNull @Size(min = 1) Stop<I, O>... stops) {
+ this.stops = stops;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Map<String, Object> toValueObject() {
+ Map<String, Object> map = super.toValueObject();
+ map.put("stops", toValueObjects(stops));
+ return map;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getTypeName() {
+ return "categorical";
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Iterator<Stop<I, O>> iterator() {
+ return Arrays.asList(stops).iterator();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int size() {
+ return stops.length;
+ }
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/CompositeStops.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/CompositeStops.java
new file mode 100644
index 0000000000..7e2ce94fe1
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/CompositeStops.java
@@ -0,0 +1,151 @@
+package com.mapbox.mapboxsdk.style.functions.stops;
+
+import android.support.annotation.Keep;
+import android.support.annotation.NonNull;
+import android.support.annotation.Size;
+
+import com.mapbox.mapboxsdk.style.functions.stops.Stop.CompositeValue;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * The {@link Stops} implementation for composite functions
+ *
+ * @param <Z> the zoom type (usually Float)
+ * @param <I> the input type (the feature property type)
+ * @param <O> the output type (the property type)
+ * @param <S> the {@link Stops} implementation (eg CategoricalStops, {@link ExponentialStops} or {@link IntervalStops})
+ */
+public class CompositeStops<Z extends Number, I, O, S extends IterableStops<I, O, Stop<I, O>>>
+ extends IterableStops<CompositeValue<Z, I>, O, Map.Entry<Z, S>> {
+
+ private final Map<Z, S> stops;
+
+ /**
+ * JNI Constructor
+ *
+ * @param stops the stops {@link Map}
+ */
+ @Keep
+ private CompositeStops(@NonNull @Size(min = 1) Map<Z, S> stops) {
+ this.stops = stops;
+ }
+
+ /**
+ * Create composite stops for {@link ExponentialStops}. Use
+ * {@link com.mapbox.mapboxsdk.style.functions.Function#composite(String, ExponentialStops)}
+ *
+ * @param stops the stops
+ */
+ public CompositeStops(@NonNull ExponentialStops<Stop.CompositeValue<Z, I>, O> stops) {
+ this.stops = new HashMap<>();
+
+ for (Map.Entry<Z, List<Stop<I, O>>> entry : collect(stops).entrySet()) {
+ // noinspection unchecked
+ this.stops.put(entry.getKey(),
+ (S) new ExponentialStops<>(stops.getBase(), entry.getValue().toArray(new Stop[0])));
+ }
+ }
+
+ /**
+ * Create composite stops for {@link IntervalStops}.
+ * Use {@link com.mapbox.mapboxsdk.style.functions.Function#composite(String, IntervalStops)}
+ *
+ * @param stops the stops
+ */
+ public CompositeStops(@NonNull IntervalStops<Stop.CompositeValue<Z, I>, O> stops) {
+ this.stops = new HashMap<>();
+
+ for (Map.Entry<Z, List<Stop<I, O>>> entry : collect(stops).entrySet()) {
+ // noinspection unchecked
+ this.stops.put(entry.getKey(), (S) new IntervalStops<>(entry.getValue().toArray(new Stop[0])));
+ }
+ }
+
+ /**
+ * Create composite stops for {@link CategoricalStops}.
+ * Use {@link com.mapbox.mapboxsdk.style.functions.Function#composite(String, CategoricalStops)}
+ *
+ * @param stops the stops
+ */
+ public CompositeStops(@NonNull CategoricalStops<CompositeValue<Z, I>, O> stops) {
+ this.stops = new HashMap<>();
+
+ for (Map.Entry<Z, List<Stop<I, O>>> entry : collect(stops).entrySet()) {
+ // noinspection unchecked
+ this.stops.put(entry.getKey(), (S) new CategoricalStops<>(entry.getValue().toArray(new Stop[0])));
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected String getTypeName() {
+ return stops.values().iterator().next().getTypeName();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Map<String, Object> toValueObject() {
+ Map<String, Object> map = super.toValueObject();
+
+ // Flatten and toValueObjects stops
+ // noinspection unchecked
+ map.put("stops", toValueObjects(flatten(this.stops).toArray(new Stop[0])));
+
+ return map;
+ }
+
+ @NonNull
+ private List<Stop<CompositeValue<Z, I>, O>> flatten(Map<Z, S> stops) {
+ List<Stop<CompositeValue<Z, I>, O>> flattenedStops = new ArrayList<>();
+ for (Map.Entry<Z, S> entry : stops.entrySet()) {
+ for (Stop<I, O> stop : entry.getValue()) {
+ flattenedStops.add(new Stop<>(new CompositeValue<>(entry.getKey(), stop.in), stop.out));
+ }
+ }
+ return flattenedStops;
+ }
+
+ @NonNull
+ private Map<Z, List<Stop<I, O>>> collect(
+ @NonNull IterableStops<CompositeValue<Z, I>, O, Stop<CompositeValue<Z, I>, O>> stops) {
+ Map<Z, List<Stop<I, O>>> converted = new HashMap<>();
+
+ for (Stop<CompositeValue<Z, I>, O> stop : stops) {
+ List<Stop<I, O>> stopsForZ = converted.get(stop.in.zoom);
+ if (stopsForZ == null) {
+ stopsForZ = new ArrayList<>();
+ converted.put(stop.in.zoom, stopsForZ);
+ }
+
+ stopsForZ.add(new Stop<>(stop.in.value, stop.out));
+ }
+
+ return converted;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Iterator<Map.Entry<Z, S>> iterator() {
+ return stops.entrySet().iterator();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int size() {
+ return stops.size();
+ }
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/ExponentialStops.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/ExponentialStops.java
new file mode 100644
index 0000000000..d47aa1fc91
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/ExponentialStops.java
@@ -0,0 +1,97 @@
+package com.mapbox.mapboxsdk.style.functions.stops;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Size;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * The {@link Stops} implementation for exponential functions
+ *
+ * @param <I> the input type
+ * @param <O> the output type
+ */
+public class ExponentialStops<I, O> extends IterableStops<I, O, Stop<I, O>> {
+
+ private float base;
+ private final Stop<I, O>[] stops;
+
+ /**
+ * Create exponential stops with an explicit base. Use through {@link Stops#exponential(Stop[])}
+ *
+ * @param base The exponential base of the interpolation curve. It controls the rate at which the function output
+ * increases. Higher values make the output increase more towards the high end of the range.
+ * With values close to 1 the output increases linearly.
+ * @param stops the stops
+ */
+ @SafeVarargs
+ public ExponentialStops(Float base, @NonNull @Size(min = 1) Stop<I, O>... stops) {
+ this.base = base != null ? base : 1.0f;
+ this.stops = stops;
+ }
+
+ /**
+ * Create exponential stops without an explicit base. Use through {@link Stops#exponential(Stop[])}
+ *
+ * @param stops the stops
+ */
+ @SafeVarargs
+ public ExponentialStops(@NonNull @Size(min = 1) Stop<I, O>... stops) {
+ this(null, stops);
+ }
+
+ /**
+ * Set the exponential base
+ *
+ * @param base the base to use in the exponential function
+ * @return this (for chaining)
+ */
+ public ExponentialStops<I, O> withBase(float base) {
+ this.base = base;
+ return this;
+ }
+
+ /**
+ * @return The exponential base
+ */
+ public float getBase() {
+ return base;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Map<String, Object> toValueObject() {
+ Map<String, Object> map = super.toValueObject();
+ map.put("base", base);
+ map.put("stops", toValueObjects(stops));
+ return map;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getTypeName() {
+ return "exponential";
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Iterator<Stop<I, O>> iterator() {
+ return Arrays.asList(stops).iterator();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int size() {
+ return stops.length;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IdentityStops.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IdentityStops.java
new file mode 100644
index 0000000000..2c0b198dc2
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IdentityStops.java
@@ -0,0 +1,18 @@
+package com.mapbox.mapboxsdk.style.functions.stops;
+
+/**
+ * The {@link Stops} implementation for identity functions
+ *
+ * @param <T> the input/output type
+ */
+public class IdentityStops<T> extends Stops<T, T> {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected String getTypeName() {
+ return "identity";
+ }
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IntervalStops.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IntervalStops.java
new file mode 100644
index 0000000000..9d95b3f8c1
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IntervalStops.java
@@ -0,0 +1,58 @@
+package com.mapbox.mapboxsdk.style.functions.stops;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Size;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * The {@link Stops} implementation for interval functions
+ *
+ * @param <I> the input type
+ * @param <O> the output type
+ */
+public class IntervalStops<I, O> extends IterableStops<I, O, Stop<I, O>> {
+
+ private final Stop<I, O>[] stops;
+
+ @SafeVarargs
+ public IntervalStops(@NonNull @Size(min = 1) Stop<I, O>... stops) {
+ this.stops = stops;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getTypeName() {
+ return "interval";
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Map<String, Object> toValueObject() {
+ Map<String, Object> map = super.toValueObject();
+ map.put("stops", toValueObjects(stops));
+ return map;
+ }
+
+ /**
+ * @return an {@link Iterator} for the contained stops
+ */
+ @Override
+ public Iterator<Stop<I, O>> iterator() {
+ return Arrays.asList(stops).iterator();
+ }
+
+ /**
+ * @return The number of contained stops
+ */
+ @Override
+ public int size() {
+ return stops.length;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IterableStops.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IterableStops.java
new file mode 100644
index 0000000000..8c5a6e8913
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IterableStops.java
@@ -0,0 +1,52 @@
+package com.mapbox.mapboxsdk.style.functions.stops;
+
+import java.util.Iterator;
+
+/**
+ * Base class for {@link Stops} implementations with a collection of stops
+ *
+ * @param <I> the {@link Stops} input type
+ * @param <O> the {@link Stops} output type
+ * @param <S> the {@link Iterable} element type (usually {@link Stop})
+ */
+public abstract class IterableStops<I, O, S> extends Stops<I, O> implements Iterable<S> {
+
+ /**
+ * @return The size of the contained stops collection
+ */
+ public abstract int size();
+
+ /**
+ * Convenience function to toValueObjects an array of stops to an array of value objects
+ *
+ * @param stops the stops to toValueObjects
+ * @return the stops as value objects
+ */
+ Object[] toValueObjects(Stop<I, O>[] stops) {
+ if (stops != null) {
+ Object[] stopsValue = new Object[stops.length];
+
+ for (int i = 0; i < stopsValue.length; i++) {
+ Stop stop = stops[i];
+ stopsValue[i] = stop.toValueObject();
+ }
+ return stopsValue;
+ }
+
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder buffer = new StringBuilder();
+ Iterator<S> iterator = iterator();
+ while (iterator.hasNext()) {
+ S stop = iterator.next();
+ buffer.append(stop);
+ if (iterator.hasNext()) {
+ buffer.append(",");
+ }
+ }
+ return String.format("%s: [%s]", super.toString(), buffer.toString());
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/Stop.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/Stop.java
new file mode 100644
index 0000000000..80825ccf6d
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/Stop.java
@@ -0,0 +1,109 @@
+package com.mapbox.mapboxsdk.style.functions.stops;
+
+import com.mapbox.mapboxsdk.style.functions.Function;
+import com.mapbox.mapboxsdk.style.layers.PropertyValue;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A stop represents a certain point in the range of this function
+ *
+ * @param <I> input the stop (function) input type
+ * @param <O> output the stop (function) output type
+ * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#types-function">The style specification</a>
+ */
+public class Stop<I, O> {
+ /**
+ * Creates a {@link Stop} to use in a {@link Function}
+ *
+ * @param in the input for the stop
+ * @param output the output for the stop
+ * @param <I> the input property type
+ * @param <O> the output property type
+ * @return the {@link Stop}
+ */
+ public static <I, O> Stop<I, O> stop(I in, PropertyValue<O> output) {
+ return new Stop<>(in, output.value);
+ }
+
+ /**
+ * Create a composite {@link Stop} for use in a {@link com.mapbox.mapboxsdk.style.functions.CompositeFunction}
+ *
+ * @param zoom the zoom input
+ * @param value the feature property input
+ * @param output the output for the stop
+ * @param <Z> the zoom type
+ * @param <I> the feature property input type
+ * @param <O> the output property type
+ * @return the {@link Stop}
+ * @see Function#composite(String, ExponentialStops)
+ */
+ public static <Z extends Number, I, O> Stop<Stop.CompositeValue<Z, I>, O> stop(Z zoom,
+ I value,
+ PropertyValue<O> output) {
+ return new Stop<>(new Stop.CompositeValue<>(zoom, value), output.value);
+ }
+
+ /**
+ * Represents a composite input value for composite functions (eg zoom and feature property value)
+ *
+ * @param <Z> the zoom input type (typically Float)
+ * @param <V> the feature property input type
+ */
+ public static class CompositeValue<Z extends Number, V> {
+ Z zoom;
+ V value;
+
+ CompositeValue(Z zoom, V value) {
+ this.zoom = zoom;
+ this.value = value;
+ }
+
+ /**
+ * INTERNAL USAGE ONLY
+ *
+ * @return the value object representation for core conversion
+ */
+ Map<String, Object> toValueObject() {
+ HashMap<String, Object> map = new HashMap<>();
+ map.put("zoom", zoom);
+ map.put("value", value);
+ return map;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("[zoom: %s, value: %s]", zoom, value);
+ }
+ }
+
+ /**
+ * The input type
+ */
+ public final I in;
+
+ /**
+ * The output type
+ */
+ public final O out;
+
+ Stop(I in, O out) {
+ this.in = in;
+ this.out = out;
+ }
+
+ /**
+ * INTERNAL USAGE ONLY
+ *
+ * @return an array representation of the Stop
+ */
+ Object[] toValueObject() {
+ return new Object[] {in instanceof CompositeValue ? ((CompositeValue) in).toValueObject() : in, out};
+ }
+
+ @Override
+ public String toString() {
+ return String.format("[%s, %s]", in, out);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/Stops.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/Stops.java
new file mode 100644
index 0000000000..a9d8055084
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/Stops.java
@@ -0,0 +1,97 @@
+package com.mapbox.mapboxsdk.style.functions.stops;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Size;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The base class for different stops implementations
+ *
+ * @param <I> the input type
+ * @param <O> the output type
+ * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#types-function">The style specification</a>
+ */
+public abstract class Stops<I, O> {
+
+ /**
+ * Convenience method for use in function declarations
+ *
+ * @param stops the collections of discrete stops
+ * @param <I> the Stops input type
+ * @param <O> the Stops output type
+ * @return the {@link Stops} implementation
+ * @see Stop#stop
+ * @see CategoricalStops
+ */
+ @SafeVarargs
+ public static <I, O> CategoricalStops<I, O> categorical(@NonNull @Size(min = 1) Stop<I, O>... stops) {
+ return new CategoricalStops<>(stops);
+ }
+
+ /**
+ * Convenience method for use in function declarations
+ *
+ * @param stops the collections of discrete stops
+ * @param <I> the Stops input type
+ * @param <O> the Stops output type
+ * @return the {@link Stops} implementation
+ * @see Stop#stop
+ * @see ExponentialStops
+ */
+ @SafeVarargs
+ public static <I, O> ExponentialStops<I, O> exponential(@NonNull @Size(min = 1) Stop<I, O>... stops) {
+ return new ExponentialStops<>(stops);
+ }
+
+ /**
+ * Convenience method for use in function declarations
+ *
+ * @param <T> the Stops input/output type
+ * @return the {@link IdentityStops} implementation
+ * @see Stop#stop
+ * @see IdentityStops
+ */
+ public static <T> IdentityStops<T> identity() {
+ return new IdentityStops<>();
+ }
+
+ /**
+ * Convenience method for use in function declarations
+ *
+ * @param stops the collections of discrete stops
+ * @param <I> the Stops input type
+ * @param <O> the Stops output type
+ * @return the {@link Stops} implementation
+ * @see Stop#stop
+ * @see IntervalStops
+ */
+ @SafeVarargs
+ public static <I, O> IntervalStops<I, O> interval(@NonNull @Size(min = 1) Stop<I, O>... stops) {
+ return new IntervalStops<>(stops);
+ }
+
+ /**
+ * INTERNAL USAGE ONLY
+ *
+ * @return the value object representation for conversion to core
+ */
+ public Map<String, Object> toValueObject() {
+ HashMap<String, Object> map = new HashMap<>();
+ map.put("type", getTypeName());
+ return map;
+ }
+
+ /**
+ * INTERNAL USAGE ONLY
+ *
+ * @return the unique type name as a string according to the style specification
+ */
+ protected abstract String getTypeName();
+
+ @Override
+ public String toString() {
+ return getTypeName();
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/package-info.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/package-info.java
new file mode 100644
index 0000000000..fa388a9589
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * Contains the Mapbox Maps Android Style Function Stop implementation API classes.
+ *
+ * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#types-function">The style specification</a>
+ */
+package com.mapbox.mapboxsdk.style.functions.stops;